Skip to content

Commit

Permalink
Merge pull request #11646 from NixOS/mergify/bp/2.21-maintenance/pr-1…
Browse files Browse the repository at this point in the history
…1610

fix passing CA files into builtins:fetchurl sandbox (backport #11610)
  • Loading branch information
roberth authored Oct 13, 2024
2 parents 08adfad + 2790f86 commit d7eaeaf
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 12 deletions.
21 changes: 14 additions & 7 deletions src/libstore/build/local-derivation-goal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1734,13 +1734,20 @@ void LocalDerivationGoal::runChild()

bool setUser = true;

/* Make the contents of netrc available to builtin:fetchurl
(which may run under a different uid and/or in a sandbox). */
/* Make the contents of netrc and the CA certificate bundle
available to builtin:fetchurl (which may run under a
different uid and/or in a sandbox). */
std::string netrcData;
try {
if (drv->isBuiltin() && drv->builder == "builtin:fetchurl")
netrcData = readFile(settings.netrcFile);
} catch (SystemError &) { }
std::string caFileData;
if (drv->isBuiltin() && drv->builder == "builtin:fetchurl") {
try {
netrcData = readFile(settings.netrcFile);
} catch (SystemError &) { }

try {
caFileData = readFile(settings.caFile);
} catch (SystemError &) { }
}

#if __linux__
if (useChroot) {
Expand Down Expand Up @@ -2169,7 +2176,7 @@ void LocalDerivationGoal::runChild()
worker.store.printStorePath(scratchOutputs.at(e.first)));

if (drv->builder == "builtin:fetchurl")
builtinFetchurl(*drv, outputs, netrcData);
builtinFetchurl(*drv, outputs, netrcData, caFileData);
else if (drv->builder == "builtin:buildenv")
builtinBuildenv(*drv, outputs);
else if (drv->builder == "builtin:unpack-channel")
Expand Down
3 changes: 2 additions & 1 deletion src/libstore/builtins.hh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ namespace nix {
void builtinFetchurl(
const BasicDerivation & drv,
const std::map<std::string, Path> & outputs,
const std::string & netrcData);
const std::string & netrcData,
const std::string & caFileData);

void builtinUnpackChannel(
const BasicDerivation & drv,
Expand Down
6 changes: 5 additions & 1 deletion src/libstore/builtins/fetchurl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ namespace nix {
void builtinFetchurl(
const BasicDerivation & drv,
const std::map<std::string, Path> & outputs,
const std::string & netrcData)
const std::string & netrcData,
const std::string & caFileData)
{
/* Make the host's netrc data available. Too bad curl requires
this to be stored in a file. It would be nice if we could just
Expand All @@ -19,6 +20,9 @@ void builtinFetchurl(
writeFile(settings.netrcFile, netrcData, 0600);
}

settings.caFile = "ca-certificates.crt";
writeFile(settings.caFile, caFileData, 0600);

auto out = get(drv.outputs, "out");
if (!out)
throw Error("'builtin:fetchurl' requires an 'out' output");
Expand Down
12 changes: 9 additions & 3 deletions tests/nixos/fetchurl.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Test whether builtin:fetchurl properly performs TLS certificate
# checks on HTTPS servers.

{ lib, config, pkgs, ... }:
{ pkgs, ... }:

let

Expand All @@ -25,7 +25,7 @@ in
name = "nss-preload";

nodes = {
machine = { lib, pkgs, ... }: {
machine = { pkgs, ... }: {
services.nginx = {
enable = true;

Expand Down Expand Up @@ -60,19 +60,25 @@ in
};
};

testScript = { nodes, ... }: ''
testScript = ''
machine.wait_for_unit("nginx")
machine.wait_for_open_port(443)
out = machine.succeed("curl https://good/index.html")
assert out == "hello world\n"
out = machine.succeed("cat ${badCert}/cert.pem > /tmp/cafile.pem; curl --cacert /tmp/cafile.pem https://bad/index.html")
assert out == "foobar\n"
# Fetching from a server with a trusted cert should work.
machine.succeed("nix build --no-substitute --expr 'import <nix/fetchurl.nix> { url = \"https://good/index.html\"; hash = \"sha256-qUiQTy8PR5uPgZdpSzAYSw0u0cHNKh7A+4XSmaGSpEc=\"; }'")
# Fetching from a server with an untrusted cert should fail.
err = machine.fail("nix build --no-substitute --expr 'import <nix/fetchurl.nix> { url = \"https://bad/index.html\"; hash = \"sha256-rsBwZF/lPuOzdjBZN2E08FjMM3JHyXit0Xi2zN+wAZ8=\"; }' 2>&1")
print(err)
assert "SSL certificate problem: self-signed certificate" in err
# Fetching from a server with a trusted cert should work via environment variable override.
machine.succeed("NIX_SSL_CERT_FILE=/tmp/cafile.pem nix build --no-substitute --expr 'import <nix/fetchurl.nix> { url = \"https://bad/index.html\"; hash = \"sha256-rsBwZF/lPuOzdjBZN2E08FjMM3JHyXit0Xi2zN+wAZ8=\"; }'")
'';
}

0 comments on commit d7eaeaf

Please sign in to comment.