mirror of
https://github.com/NixOS/nix
synced 2025-06-30 15:48:00 +02:00
Merge pull request #11693 from NixOS/backport-11610-to-2.19-maintenance
Backport #11610 to 2.19 maintenance
This commit is contained in:
commit
52166fd12e
7 changed files with 105 additions and 34 deletions
|
@ -1740,14 +1740,21 @@ void LocalDerivationGoal::runChild()
|
||||||
|
|
||||||
bool setUser = true;
|
bool setUser = true;
|
||||||
|
|
||||||
/* Make the contents of netrc available to builtin:fetchurl
|
/* Make the contents of netrc and the CA certificate bundle
|
||||||
(which may run under a different uid and/or in a sandbox). */
|
available to builtin:fetchurl (which may run under a
|
||||||
|
different uid and/or in a sandbox). */
|
||||||
std::string netrcData;
|
std::string netrcData;
|
||||||
|
std::string caFileData;
|
||||||
|
if (drv->isBuiltin() && drv->builder == "builtin:fetchurl") {
|
||||||
try {
|
try {
|
||||||
if (drv->isBuiltin() && drv->builder == "builtin:fetchurl")
|
|
||||||
netrcData = readFile(settings.netrcFile);
|
netrcData = readFile(settings.netrcFile);
|
||||||
} catch (SysError &) { }
|
} catch (SysError &) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
caFileData = readFile(settings.caFile);
|
||||||
|
} catch (SysError &) { }
|
||||||
|
}
|
||||||
|
|
||||||
#if __linux__
|
#if __linux__
|
||||||
if (useChroot) {
|
if (useChroot) {
|
||||||
|
|
||||||
|
@ -1848,11 +1855,18 @@ void LocalDerivationGoal::runChild()
|
||||||
if (pathExists(path))
|
if (pathExists(path))
|
||||||
ss.push_back(path);
|
ss.push_back(path);
|
||||||
|
|
||||||
if (settings.caFile != "")
|
if (settings.caFile != "" && pathExists(settings.caFile)) {
|
||||||
pathsInChroot.try_emplace("/etc/ssl/certs/ca-certificates.crt", settings.caFile, true);
|
Path caFile = settings.caFile;
|
||||||
|
pathsInChroot.try_emplace("/etc/ssl/certs/ca-certificates.crt", canonPath(caFile, true), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto & i : ss) pathsInChroot.emplace(i, i);
|
for (auto & i : ss) {
|
||||||
|
// For backwards-compatibiliy, resolve all the symlinks in the
|
||||||
|
// chroot paths
|
||||||
|
auto canonicalPath = canonPath(i, true);
|
||||||
|
pathsInChroot.emplace(i, canonicalPath);
|
||||||
|
}
|
||||||
|
|
||||||
/* Bind-mount all the directories from the "host"
|
/* Bind-mount all the directories from the "host"
|
||||||
filesystem that we want in the chroot
|
filesystem that we want in the chroot
|
||||||
|
@ -2174,7 +2188,7 @@ void LocalDerivationGoal::runChild()
|
||||||
e.second = rewriteStrings(e.second, inputRewrites);
|
e.second = rewriteStrings(e.second, inputRewrites);
|
||||||
|
|
||||||
if (drv->builder == "builtin:fetchurl")
|
if (drv->builder == "builtin:fetchurl")
|
||||||
builtinFetchurl(drv2, netrcData);
|
builtinFetchurl(drv2, netrcData, caFileData);
|
||||||
else if (drv->builder == "builtin:buildenv")
|
else if (drv->builder == "builtin:buildenv")
|
||||||
builtinBuildenv(drv2);
|
builtinBuildenv(drv2);
|
||||||
else if (drv->builder == "builtin:unpack-channel")
|
else if (drv->builder == "builtin:unpack-channel")
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
// TODO: make pluggable.
|
// TODO: make pluggable.
|
||||||
void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData);
|
void builtinFetchurl(const BasicDerivation & drv,
|
||||||
|
const std::string & netrcData,
|
||||||
|
const std::string & caFileData);
|
||||||
void builtinUnpackChannel(const BasicDerivation & drv);
|
void builtinUnpackChannel(const BasicDerivation & drv);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,10 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
|
void builtinFetchurl(
|
||||||
|
const BasicDerivation & drv,
|
||||||
|
const std::string & netrcData,
|
||||||
|
const std::string & caFileData)
|
||||||
{
|
{
|
||||||
/* Make the host's netrc data available. Too bad curl requires
|
/* 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
|
this to be stored in a file. It would be nice if we could just
|
||||||
|
@ -16,6 +19,9 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData)
|
||||||
writeFile(settings.netrcFile, netrcData, 0600);
|
writeFile(settings.netrcFile, netrcData, 0600);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
settings.caFile = "ca-certificates.crt";
|
||||||
|
writeFile(settings.caFile, caFileData, 0600);
|
||||||
|
|
||||||
auto getAttr = [&](const std::string & name) {
|
auto getAttr = [&](const std::string & name) {
|
||||||
auto i = drv.env.find(name);
|
auto i = drv.env.find(name);
|
||||||
if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
|
if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
|
||||||
|
|
|
@ -50,6 +50,8 @@ struct curlFileTransfer : public FileTransfer
|
||||||
bool done = false; // whether either the success or failure function has been called
|
bool done = false; // whether either the success or failure function has been called
|
||||||
Callback<FileTransferResult> callback;
|
Callback<FileTransferResult> callback;
|
||||||
CURL * req = 0;
|
CURL * req = 0;
|
||||||
|
// buffer to accompany the `req` above
|
||||||
|
char errbuf[CURL_ERROR_SIZE];
|
||||||
bool active = false; // whether the handle has been added to the multi object
|
bool active = false; // whether the handle has been added to the multi object
|
||||||
std::string statusMsg;
|
std::string statusMsg;
|
||||||
|
|
||||||
|
@ -352,6 +354,9 @@ struct curlFileTransfer : public FileTransfer
|
||||||
if (writtenToSink)
|
if (writtenToSink)
|
||||||
curl_easy_setopt(req, CURLOPT_RESUME_FROM_LARGE, writtenToSink);
|
curl_easy_setopt(req, CURLOPT_RESUME_FROM_LARGE, writtenToSink);
|
||||||
|
|
||||||
|
curl_easy_setopt(req, CURLOPT_ERRORBUFFER, errbuf);
|
||||||
|
errbuf[0] = 0;
|
||||||
|
|
||||||
result.data.clear();
|
result.data.clear();
|
||||||
result.bodySize = 0;
|
result.bodySize = 0;
|
||||||
}
|
}
|
||||||
|
@ -465,8 +470,8 @@ struct curlFileTransfer : public FileTransfer
|
||||||
code == CURLE_OK ? "" : fmt(" (curl error: %s)", curl_easy_strerror(code)))
|
code == CURLE_OK ? "" : fmt(" (curl error: %s)", curl_easy_strerror(code)))
|
||||||
: FileTransferError(err,
|
: FileTransferError(err,
|
||||||
std::move(response),
|
std::move(response),
|
||||||
"unable to %s '%s': %s (%d)",
|
"unable to %s '%s': %s (%d) %s",
|
||||||
request.verb(), request.uri, curl_easy_strerror(code), code);
|
request.verb(), request.uri, curl_easy_strerror(code), code, errbuf);
|
||||||
|
|
||||||
/* If this is a transient error, then maybe retry the
|
/* If this is a transient error, then maybe retry the
|
||||||
download after a while. If we're writing to a
|
download after a while. If we're writing to a
|
||||||
|
|
|
@ -60,7 +60,13 @@ testCert () {
|
||||||
|
|
||||||
nocert=$TEST_ROOT/no-cert-file.pem
|
nocert=$TEST_ROOT/no-cert-file.pem
|
||||||
cert=$TEST_ROOT/some-cert-file.pem
|
cert=$TEST_ROOT/some-cert-file.pem
|
||||||
|
symlinkcert=$TEST_ROOT/symlink-cert-file.pem
|
||||||
|
transitivesymlinkcert=$TEST_ROOT/transitive-symlink-cert-file.pem
|
||||||
|
symlinkDir=$TEST_ROOT/symlink-dir
|
||||||
echo -n "CERT_CONTENT" > $cert
|
echo -n "CERT_CONTENT" > $cert
|
||||||
|
ln -s $cert $symlinkcert
|
||||||
|
ln -s $symlinkcert $transitivesymlinkcert
|
||||||
|
ln -s $TEST_ROOT $symlinkDir
|
||||||
|
|
||||||
# No cert in sandbox when not a fixed-output derivation
|
# No cert in sandbox when not a fixed-output derivation
|
||||||
testCert missing normal "$cert"
|
testCert missing normal "$cert"
|
||||||
|
@ -74,5 +80,14 @@ testCert missing fixed-output "$nocert"
|
||||||
# Cert in sandbox when ssl-cert-file is set to an existing file
|
# Cert in sandbox when ssl-cert-file is set to an existing file
|
||||||
testCert present fixed-output "$cert"
|
testCert present fixed-output "$cert"
|
||||||
|
|
||||||
|
# Cert in sandbox when ssl-cert-file is set to a (potentially transitive) symlink to an existing file
|
||||||
|
testCert present fixed-output "$symlinkcert"
|
||||||
|
testCert present fixed-output "$transitivesymlinkcert"
|
||||||
|
|
||||||
# Symlinks should be added in the sandbox directly and not followed
|
# Symlinks should be added in the sandbox directly and not followed
|
||||||
nix-sandbox-build symlink-derivation.nix
|
nix-sandbox-build symlink-derivation.nix -A depends_on_symlink
|
||||||
|
nix-sandbox-build symlink-derivation.nix -A test_sandbox_paths \
|
||||||
|
--option extra-sandbox-paths "/file=$cert" \
|
||||||
|
--option extra-sandbox-paths "/dir=$TEST_ROOT" \
|
||||||
|
--option extra-sandbox-paths "/symlinkDir=$symlinkDir" \
|
||||||
|
--option extra-sandbox-paths "/symlink=$symlinkcert"
|
||||||
|
|
|
@ -15,7 +15,8 @@ let
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
mkDerivation {
|
{
|
||||||
|
depends_on_symlink = mkDerivation {
|
||||||
name = "depends-on-symlink";
|
name = "depends-on-symlink";
|
||||||
buildCommand = ''
|
buildCommand = ''
|
||||||
(
|
(
|
||||||
|
@ -30,7 +31,29 @@ mkDerivation {
|
||||||
[[ -L ${symlink_to_not_in_store} ]]
|
[[ -L ${symlink_to_not_in_store} ]]
|
||||||
[[ $(readlink ${symlink_to_not_in_store}) == ${builtins.toString ./.} ]]
|
[[ $(readlink ${symlink_to_not_in_store}) == ${builtins.toString ./.} ]]
|
||||||
(! ls ${symlink_to_not_in_store}/)
|
(! ls ${symlink_to_not_in_store}/)
|
||||||
|
|
||||||
|
# Native paths
|
||||||
)
|
)
|
||||||
echo "Success!" > $out
|
echo "Success!" > $out
|
||||||
'';
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
test_sandbox_paths = mkDerivation {
|
||||||
|
# Depends on the caller to set a bunch of `--sandbox-path` arguments
|
||||||
|
name = "test-sandbox-paths";
|
||||||
|
buildCommand = ''
|
||||||
|
(
|
||||||
|
set -x
|
||||||
|
[[ -f /file ]]
|
||||||
|
[[ -d /dir ]]
|
||||||
|
|
||||||
|
# /symlink and /symlinkDir should be available as raw symlinks
|
||||||
|
# (pointing to files outside of the sandbox)
|
||||||
|
[[ -L /symlink ]] && [[ ! -e $(readlink /symlink) ]]
|
||||||
|
[[ -L /symlinkDir ]] && [[ ! -e $(readlink /symlinkDir) ]]
|
||||||
|
)
|
||||||
|
|
||||||
|
touch $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Test whether builtin:fetchurl properly performs TLS certificate
|
# Test whether builtin:fetchurl properly performs TLS certificate
|
||||||
# checks on HTTPS servers.
|
# checks on HTTPS servers.
|
||||||
|
|
||||||
{ lib, config, pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ in
|
||||||
name = "nss-preload";
|
name = "nss-preload";
|
||||||
|
|
||||||
nodes = {
|
nodes = {
|
||||||
machine = { lib, pkgs, ... }: {
|
machine = { pkgs, ... }: {
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
|
@ -60,13 +60,16 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = { nodes, ... }: ''
|
testScript = ''
|
||||||
machine.wait_for_unit("nginx")
|
machine.wait_for_unit("nginx")
|
||||||
machine.wait_for_open_port(443)
|
machine.wait_for_open_port(443)
|
||||||
|
|
||||||
out = machine.succeed("curl https://good/index.html")
|
out = machine.succeed("curl https://good/index.html")
|
||||||
assert out == "hello world\n"
|
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.
|
# 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=\"; }'")
|
machine.succeed("nix build --no-substitute --expr 'import <nix/fetchurl.nix> { url = \"https://good/index.html\"; hash = \"sha256-qUiQTy8PR5uPgZdpSzAYSw0u0cHNKh7A+4XSmaGSpEc=\"; }'")
|
||||||
|
|
||||||
|
@ -74,5 +77,8 @@ in
|
||||||
err = machine.fail("nix build --no-substitute --expr 'import <nix/fetchurl.nix> { url = \"https://bad/index.html\"; hash = \"sha256-rsBwZF/lPuOzdjBZN2E08FjMM3JHyXit0Xi2zN+wAZ8=\"; }' 2>&1")
|
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)
|
print(err)
|
||||||
assert "SSL certificate problem: self-signed certificate" in 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=\"; }'")
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue