If bash is executed within an environment where PATH is not set, it uses
the DEFAULT_PATH_VALUE compiled into bash to set PATH. In nixpkgs we set
this to /no-such-path by default. This makes sense in a nixpkgs/NixOS
environment since paths like /bin or /usr/bin should not be used.
However, when bash is used inside an FHS environment, this produces
results that differ from distributions which follow the FHS standard.
Before this change:
$ steam-run env -i /bin/bash -c 'echo $PATH'
/no-such-path
After this change:
$ steam-run env -i /bin/bash -c 'echo $PATH'
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:.
buildFHSUserEnv is meant primarily for running 3rd-party software
which is difficult to patch for NixOS. Such software is often built to
run from /opt. Currently, running such a software from FHS environment
is difficult for two reasons:
1. If the 3rd-party software is put into the Nix store via a simple
derivation (with e.g. installPhase = "dpkg-deb -x $src $out"), the
content of /opt directory of that derivation does not appear in the
FHSEnv even if the derivation is specified in targetPkgs. This is
why we change env.nix.
2. If using buildFHSUserEnvChroot and the host system has the /opt
directory, it always gets bind-mounted to the FHSEnv even if some
targetPkgs contain /opt (NB buildFHSUserEnvBubblewrap does not have
this problem). If that directory is not accessible for non-root
users (which is what docker's containerd does with /opt :-(), the
user running the FHSEnv cannot use it.
With the change in chrootenv.c, /opt is not bind-mounted to the
container, but instead created as user-modifiable symlink to
/host/opt (see the init attribute in
build-fhs-userenv/default.nix). If needed, the user can remove this
symlink and create an empty /opt directory which is under his/her
control.
I hate the thing too even though I made it, and rather just get rid of
it. But we can't do that yet. In the meantime, this brings us more
inline with autoconf and will make it slightly easier for me to write a
pkg-config wrapper, which we need.
Naive concatenation of $LD_LIBRARY_PATH can result in an empty
colon-delimited segment; this tells glibc to load libraries from the
current directory, which is definitely wrong, and may be a security
vulnerability if the current directory is untrusted. (See #67234, for
example.) Fix this throughout the tree.
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
This takes another approach at binding FHS directory structure. We
now bind-mount all the root filesystem to directory "/host" in the target tree.
From that we symlink all the directories into the tree if they do not already
exist in FHS structure.
This probably makes `CHROOTENV_EXTRA_BINDS` unnecessary -- its main usecase was
to add bound directories from the host to the sandbox, and we not just symlink
all of them. I plan to get some feedback on its usage and maybe deprecate it.
This also drops old `buildFHSChrootEnv` infrastructure. The main problem with it
is it's very difficult to unmount a recursive-bound directory when mount is not
sandboxed. This problem is a bug even without these changes -- if
you have for example `/home/alice` mounted to somewhere, you wouldn't see
it in `buildFHSChrootEnv` now. With the new directory structure, it's
impossible to use regular bind at all. After some tackling with this I realized
that the fix would be brittle and dangerous (if you don't unmount everything
clearly and proceed to removing the temporary directory, bye-bye fs!). It also
probably doesn't worth it because I haven't heard that someone actually uses it
for a long time, and `buildFHSUserEnv` should cover most cases while being much
more maintainable and safe for the end-user.