Add /bin/bash to avoid unnecessary pain

/bin/bash is still impure.

if you really want a “quick and dirty”, you can always do:

nix-shell -p steam-run --run "steam-run <program>"
4 Likes

I don’t want quick and dirty. I just want a minimum of unsolvable puzzles.

Like:
[ 85%] Generating asn1.cert.pem, coordinates.bin, ec_cert_with_ext.pem, ec_cert_crl_distribution.pem, intermediate.crl.der, intermediate.cert.pem, intermediate.ec.cert.pem, intermediate2.cert.pem, leaf.key.pem, leaf.cert.pem, leaf.ec.cert.pem, leaf.public.key.pem, leaf_modulus.hex, leaf2.cert.pem, root.crl.der, root.cert.pem, root.ec.cert.pem, root.ec.key.pem, root.ec.public.key.pem, root2.cert.pem, self_signed.cert.der, test_ec_signature, test_rsa_signature, time.txt
cd /nix/store/78rvpsgfp9g92sl30620ywr4239mwwpa-openenclave-sdk/tests/crypto/data && /nix/store/k8p54jg8ipvnfz435mayf5bnqhw4qqap-bash-4.4-p23/bin/bash -c /nix/store/myjxqm5qbx9gsq6spvcy73hac5rwj89w-source/tests/crypto/data/make-test-certs\ /nix/store/myjxqm5qbx9gsq6spvcy73hac5rwj89w-source/tests/crypto/data\ /nix/store/78rvpsgfp9g92sl30620ywr4239mwwpa-openenclave-sdk/tests/crypto/data\ –bash
/nix/store/k8p54jg8ipvnfz435mayf5bnqhw4qqap-bash-4.4-p23/bin/bash: /nix/store/myjxqm5qbx9gsq6spvcy73hac5rwj89w-source/tests/crypto/data/make-test-certs: /nix/store/6h0xx5d8wwl8zf7g4x2sjl0q4hr3nnb4-bash-interactive-4.4-p23/bin/bash: bad interpreter: No such file or directory
make[2]: *** [tests/crypto/data/CMakeFiles/crypto_test_data.dir/build.make:103: tests/crypto/data/asn1.cert.pem] Error 126
make[2]: Leaving directory ‘/nix/store/78rvpsgfp9g92sl30620ywr4239mwwpa-openenclave-sdk’
make[1]: *** [CMakeFiles/Makefile2:19204: tests/crypto/data/CMakeFiles/crypto_test_data.dir/all] Error 2
make[1]: Leaving directory ‘/nix/store/78rvpsgfp9g92sl30620ywr4239mwwpa-openenclave-sdk’

This expression works fine in nix-shell --pure but something is wrong in nix-build…

I have more details in the other post (sudden EOF)…
I’ve tried adding patchShebang everywhere but no luck.

Development:

I removed the shebang altogether and it built. Apparently patchShebangs gets confused?

--pure makes the environment pure but does not chroot your shell (does not run it in a sandbox without file system access). If the project tries to use impure paths on the file system instead of relying on PATH, it will be able to access them. It is a compromise between fully hermetic build environment (like the one inside nix-build) and fully impure one with access to the environment variables set by your system.

2 Likes

I just ran into this while trying to use emacs org babel mode with tramp; i.e. interactive “notebook style” computing.

At first it looked like a silent failure, but I eventually found env: ‘/bin/bash’: No such file or directory in a nearby buffer.

I note this because I see plenty of discussion of interactions within a machine but not interactions between machines.

1 Like

maybe related, but what’s the proper solution for things like PHP which executes /bin/sh like here https://github.com/php/php-src/blob/9bbeb0555b6b842ebd44e08510ff3f3226237544/ext/standard/proc_open.c#L1210-L1215

Patching the source file.

3 Likes

This is an alternative that can add arbitrary programs to /usr/bin and /bin while not hurting purity: GitHub - Mic92/envfs: Fuse filesystem that returns symlinks to executables based on the PATH of the requesting process.

10 Likes

envfs looks really interesting.

Is it feasible to use a mechanism like that inside the build sandbox while also preserving purity there?

As I understand it that could work for build-time-only dependencies, which could be great to make things like build scripts run without tedious patching.

I would imagine for that use case it could be better to provide an explicit whitelist of paths that should be resolved from the derivation’s nativeBuildInputs than to magically resolve everything. For example:

envfsResovle = [ "/bin/bash", "/usr/bin/env" ];

@Mic92 cntr/breakpointHook uses FUSE inside the sandbox as well, right?

It would be probably easier to add them via the sandboxPath option:

nix.sandboxPaths = ["/opt" "/usr"];

I’m a bit late, but couldn’t /bin/bash just forward to the bash found in $PATH? Is a sandbox really needed for purity?

2 Likes

Actually, since in many cases the upstream change we would require would be to replace #!/bin/bash with #!/usr/bin/env bash, would there be any problems with simply putting this as /bin/bash?

#!/bin/sh
/usr/bin/env bash $@

It’s true that doing this is impure, but only as much as the #!/usr/bin/env bash hashbang would be in the first place. I’m not overly familiar with the details and gotchas with shells and hashbangs, so I’m not sure if there are more problems I can’t foresee.

7 Likes

There is a pull request to add /bin/bash to fhs-userenv:

https://github.com/NixOS/nixpkgs/pull/126448

Can someone from this thread review it? Maybe it’s fine there for purity and could solve the issue people have in this thread.

4 Likes

I know this is a blast from the past, but for those who find this article in the future I wanted to point out the explicit parts of the spec that are relevant here :

Applications should note that the standard PATH to the shell cannot be assumed to be either /bin/sh or /usr/bin/sh , and should be determined by interrogation of the PATH returned by getconf PATH, ensuring that the returned pathname is an absolute pathname and not a shell built-in.

https://pubs.opengroup.org/onlinepubs/9699919799/

As for env the poster above is correct that it is not specified where the env should be expected - my takeaway was really that #! env sh is “closer to the spec” than #! /usr/bin/env sh ( I’m not recommending that it actually be used though, because as a practical matter it causes problems ).

2 Likes

Sorry to jump into this that late, but why couldn’t we turn /bin/bash into a script that checks if a (say) NIX_IMPURE_BASH environment variable is defined, and then

  1. if it is defined, then it calls the binary specified in NIX_IMPURE_BASH with the rest of the arguments (this could either be an absolute path or a path that must be resolved using $PATH)
  2. if it is undefined them it crashes with a clear error like:
To preserve purity NixOs forbids scripts to use /bin/bash.
The recommended procedure is to properly package your scripts…
or if you really want a quick and dirty solution run:
$ export NIX_IMPURE_BASH=bash
and try again.

This way we have best of all words:

  1. it gives a clear and user friendly error to explain why the script failed together with a solution (which is not the case right now)
  2. The quick and dirty solution is accessible to beginners (and no, steam-run is not really user-friendly… if you need a program that is not already included in steam-run you have to write your own derivation and the integration is really poor with the host system)
  3. The impurity only stays located to the current shell/program and will not spread to other programs.
  4. Most users will not set NIX_IMPURE_BASH globally and therefore impurities in packaged software will be quickly spotted…
  5. … and if a user is really willing to set NIX_IMPURE_BASH globally (this should be discouraged but of course cannot be avoided) we could for instance unset NIX_IMPURE_BASH at the beginning of the build procedure and/or write a WARNING when the users is building their own software saying that impurities could arrive and that it is better to test the program with unset NIX_IMPURE_BASH first.
  6. Finally it is quite simple to program, debug and use (sandboxes or fuse are way more complicated and more dependent on the enabled kernel features)…
1 Like

Late to the party, I’ll add another argument in favor of a principled way to get a /bin/bash file: interoperability from the outside.

I’m using NixOS in other context than bare machine: VMs, local or on the cloud, and even locally on WSL.

When external tools need to interact with my NixOS system, some of them expect bash to be callable via execvpe without a login shell.

Right now, on one of these occasion, I could make it call /run/current-system/sw/bin/bash, but most of the time it is hard coded in the source code of the tool, which I may not have access to, and not configurable, especially on cloud platforms.

Being able to call /bin/bash would allow me to use NixOS in more context, especially in production. Some people will tell me that I can use Y instead of X to do my thing and it is configurable/open-source, but life isn’t always that easy, I can’t always make this change (e.g. company already committed to using X and won’t change, for very good reasons).

Would it really be less principled to define system.activationScripts.binbash by analogy to system.activationScripts.binsh, though?

Edited to add: see nixos/modules/config/shells-environment.nix for binsh

1 Like

system.activationScripts.binbash sounds reasonable to me, thanks for pointing this out.

I had missed @matthewbauer’s answer.

2 years later, I don’t quite understand why it wasn’t merged to nixpkgs
EDIT: spent a little more time reading the thread. I understand there can be challenges. I’m a bit saddened because in my position it gives another argument against NixOS in production.

In any case, thanks a lot!

1 Like

I actually do agree with volth’s suggestion to have a list of symlinks (at least that’s how I manage my not-exactly-NixOS system).

@tbenst would you be willing to edit (into the top post) a mention of @matthewbauer’s code proposal in the thread?

Is there a good reason not to add an environment variable like in nix-ld to enable/disable /bin/bash, while displaying an helpfull error message if this variable is disabled? It might help to detect impurities without significantly changing the user experience (it’s always possible to enable this environment variable by default).

4 Likes