nix icon indicating copy to clipboard operation
nix copied to clipboard

NIX_SSL_CERT_FILE unreadable from nix sandbox

Open TomaSajt opened this issue 8 months ago • 5 comments

Describe the bug

Note: this issue is partially resolved by https://github.com/NixOS/nixpkgs/pull/401942, but further discussion is needed.

The following description of the issue assumes that the workaround in https://github.com/NixOS/nixpkgs/pull/401942 is not present:


The NIX_SSL_CERT_FILE env var is used for overriding nix's ssl-cert-file config value via an env var. The NIX_SSL_CERT_FILE env var is also respected in several Nixpkgs packages (via patches) that need certificate bundles. By default, NIX_SSL_CERT_FILE used to be unset inside the build environment unless something inside nixpkgs set it to a value: the cacert hook's main job was to do this.

However after https://github.com/NixOS/nixpkgs/pull/303307 was merged into Nixpkgs, NIX_SSL_CERT_FILE was added as a default impure env var for fetchers. It also made the cacert hook respect the variable if it was not unset (in case it inherited the impure env var).

This can be useful. But only if NIX_SSL_CERT_FILE is readable.

In most cases NIX_SSL_CERT_FILE is unset by default, so it doesn't cause problems. If NIX_SSL_CERT_FILE is set to a path readable from the builder itself, it still doesn't cause problems. However, in most cases where NIX_SSL_CERT_FILE is set to anything, it is set to a path that's not readable from the builder, e.g. /etc/ssl/certs/ca-certificates.crt or /nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt.

See: The author of https://github.com/NixOS/nixpkgs/pull/303307 has a program which uses the impure env var behaviour of NIX_SSL_CERT_FILE, but it can only use it by putting the cert in the world-readable /tmp directory

Users of nix-darwin have the NIX_SSL_CERT_FILE of the nix-daemon (where impure env vars are inherited from) set by default, because security.pki.installCACerts is set to true by default. See: https://github.com/nix-darwin/nix-darwin/blob/b6fff20c692d684d250a39453ed1853dd44c96ab/modules/security/pki/default.nix#L82-L89 https://github.com/nix-darwin/nix-darwin/blob/b6fff20c692d684d250a39453ed1853dd44c96ab/modules/services/nix-daemon.nix#L63-L65

"Luckily" because darwin does not have sandboxing enabled by default, this is not a problem.

However, this means that if we enable sandboxing on darwin, we are very likely to encounter the fact that NIX_SSL_CERT_FILE is not readable from the builder.

In darwin, we could actually fix this readability issue because darwin doesn't use chroot for sandboxing, it just uses access whitelist rules. Here's a possible solution just adding the set certificate file in the allowlist: https://gerrit.lix.systems/c/lix/+/2906


NIX_SSL_CERT_FILE being unreadable breaks many things in Nixpkgs: e.g. fetchgit and rustPlatform.fetchCargoVendor, basically everything using cacert as a setup-hook.

fetchCargoVendor failure: https://github.com/NixOS/nixpkgs/issues/385366 fetchgit failure: https://github.com/NixOS/nixpkgs/issues/385366#issuecomment-2738035391


Steps To Reproduce

  1. have a nix-darwin system
  2. have sandboxing enabled
  3. in a FOD derivation, have impureEnvVars = lib.fetchers.proxyImpureEnvVars (a list that contains NIX_SSL_CERT_FILE, among others)
  4. in the FOD's build script run cat "$NIX_SSL_CERT_FILE"
  5. get a permission error (which means that it is not whitelisted by the sandbox)

Additional context

Checklist


Add :+1: to issues you find important.

TomaSajt avatar Mar 19 '25 22:03 TomaSajt

Thanks for opening this.

Repro for me:

$ nix config show sandbox
true
$ nix repl nixpkgs#legacyPackages.aarch64-darwin
Nix 2.24.12
Type :? for help.
Loading installable 'flake:nixpkgs#legacyPackages.aarch64-darwin'...
Added 24154 variables.
nix-repl> :b fetchgit { url = "https://github.com/n8henrie/flake-templates"; hash = "sha256-nkwrC+gtQ1AgD0LOmnweBs25aIErWWiv8qckplrofvk=";}
error: builder for '/nix/store/i80ansib9qpy96ydqvxx1h8vvcmfv4h0-flake-templates.drv' failed with exit code 1;
       last 7 log lines:
       > exporting https://github.com/n8henrie/flake-templates (rev HEAD) into /nix/store/ycbh64cs7finbl4z8ig7wqm1k0iydbrr-flake-templates
       > Initialized empty Git repository in /nix/store/ycbh64cs7finbl4z8ig7wqm1k0iydbrr-flake-templates/.git/
       > fatal: unable to access 'https://github.com/n8henrie/flake-templates/': SSL certificate problem: unable to get local issuer certificate
       > fatal: unable to access 'https://github.com/n8henrie/flake-templates/': SSL certificate problem: unable to get local issuer certificate
       > fatal: unable to access 'https://github.com/n8henrie/flake-templates/': SSL certificate problem: unable to get local issuer certificate
       > fatal: unable to access 'https://github.com/n8henrie/flake-templates/': SSL certificate problem: unable to get local issuer certificate
       > Unable to checkout HEAD from https://github.com/n8henrie/flake-templates.
       For full logs, run 'nix log /nix/store/i80ansib9qpy96ydqvxx1h8vvcmfv4h0-flake-templates.drv'.
error: build of '/nix/store/i9qaqh66iydxzr0sqqpkz6wvqfs63xdw-flake-templates.drv' failed
[0 built (4 failed), 0.0 MiB DL]
  • system: "aarch64-darwin"
  • host os: Darwin 24.3.0, macOS 15.3.2
  • multi-user?: yes
  • sandbox: yes
  • version: nix-env (Nix) 2.24.12
  • channels(root): "nixpkgs"
  • nixpkgs: /nix/store/6pz76h4dyj2s9il8pbrxi1knkmbs0z9a-source

n8henrie avatar Mar 21 '25 13:03 n8henrie

@WeetHet created https://gerrit.lix.systems/c/lix/+/2869 in lix that sounds like it should resolve the issue.

khaneliman avatar Mar 21 '25 21:03 khaneliman

An improved version: https://gerrit.lix.systems/c/lix/+/2906

TomaSajt avatar Mar 31 '25 19:03 TomaSajt

Thanks for raising this, the readability issue was a surprise to me.

My original line of thinking was "why would you set this to an unreadable path"? But of course these things are usually accidental or a result of other intentions.

That lix change looks good to me, thanks!

If we don't want to always expose that file, a narrower change could be for the sandbox code which makes the file unreadable to also unset the envvar. But simply making that file available in-sandbox is much better ❤ .

timbertson avatar Jun 17 '25 21:06 timbertson

When I originally posted the link to the lix "fix" the issue, I knew a lot less than what I know now, and I have since updated the issue description a lot.

Currently, I don't believe that the Lix fix is good enough, as it doesn't do anything for linux, and relies on the fact that darwin paths in the sandbox are identical to darwin paths outside of the sandbox.

I currently don't really have the bandwidth to try to come up with an ideal alternate solution, but in a few weeks, once I'm free, I will gladly discuss possible long term solutions.

Hopefully we can bring people from both NixOS/nix and Lix into the discussion.

TomaSajt avatar Jun 17 '25 21:06 TomaSajt

https://git.lix.systems/lix-project/lix/issues/885

flokli avatar Jun 27 '25 19:06 flokli

Okay, I don't know if I already sent this link or not, but I think it is important:

https://github.com/NixOS/nix/blob/acfdacc971bb411bb8b85a05a37b6fc7330c4370/src/libstore/unix/build/linux-derivation-builder.cc#L664-L668

For linux-only: the contents of whatever ssl-cert-file is set to (caFile), will appear at the hardcoded location /etc/ssl/certs/ca-certificates.crt when building a FOD.

But since NIX_SSL_CERT_FILE is not guaranteed to be set to /etc/ssl/certs/ca-certificates.crt exactly, we don't find it.

Now, we could make it place the contents of caFile to the same location as NIX_SSL_CERT_FILE, but IMO that's horrible. Another solution would be to have the process override NIX_SSL_CERT_FILE to point to the location where the contents of caFile were placed inside the chroot. This is better.

Though, I have not thought through what should happen in different sandbox modes, what should we do for backwards compat or whatever.

I still have much to do for the next 7 days, so I can't really dive much deeper now.

TomaSajt avatar Jun 27 '25 19:06 TomaSajt

Another solution would be to have the process override NIX_SSL_CERT_FILE to point to the location where the contents of caFile were placed inside the chroot. This is better.

Yes, that sounds right to me too. That way the invariant holds inside and outside of a build that NIX_SSL_CERT_FILE points to a valid cert file. That is, assuming settings.caFile comes from $NIX_SSL_CERT_FILE when set?

timbertson avatar Jun 28 '25 00:06 timbertson