Skip to content

Commit

Permalink
Fix the access of symlinks to host files in the sandbox
Browse files Browse the repository at this point in the history
NixOS#10456 fixed the addition of symlink
store paths to the sandbox, but also made it so that the hardcoded
sandbox paths (like `/etc/hosts`) were now bind-mounted without
following the possible symlinks. This made these files unreadable if
there were symlinks (because the sandbox would now contain a symlink to
an unreachable file rather than the underlying file).
In particular, this broke FOD derivations on NixOS as `/etc/hosts` is a
symlink there.

Fix that by canonicalizing all these hardcoded sandbox paths before
adding them to the sandbox.
  • Loading branch information
Théophane Hufschmitt committed Apr 12, 2024
1 parent 5b9cb8b commit acbb152
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 20 deletions.
13 changes: 10 additions & 3 deletions src/libstore/build/local-derivation-goal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1823,11 +1823,18 @@ void LocalDerivationGoal::runChild()
if (pathExists(path))
ss.push_back(path);

if (settings.caFile != "")
pathsInChroot.try_emplace("/etc/ssl/certs/ca-certificates.crt", settings.caFile, true);
if (settings.caFile != "" && pathExists(settings.caFile)) {
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"
filesystem that we want in the chroot
Expand Down
14 changes: 13 additions & 1 deletion tests/functional/linux-sandbox.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ testCert () {

nocert=$TEST_ROOT/no-cert-file.pem
cert=$TEST_ROOT/some-cert-file.pem
symlinkcert=$TEST_ROOT/symlink-cert-file.pem
symlinkDir=$TEST_ROOT/symlink-dir
echo -n "CERT_CONTENT" > $cert
ln -s $cert $symlinkcert
ln -s $TEST_ROOT $symlinkDir

# No cert in sandbox when not a fixed-output derivation
testCert missing normal "$cert"
Expand All @@ -74,5 +78,13 @@ testCert missing fixed-output "$nocert"
# Cert in sandbox when ssl-cert-file is set to an existing file
testCert present fixed-output "$cert"

# Cert in sandbox when ssl-cert-file is set to a symlink to an existing file
testCert present fixed-output "$symlinkcert"

# 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"
55 changes: 39 additions & 16 deletions tests/functional/symlink-derivation.nix
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,45 @@ let
'';
};
in
mkDerivation {
name = "depends-on-symlink";
buildCommand = ''
(
set -x
{
depends_on_symlink = mkDerivation {
name = "depends-on-symlink";
buildCommand = ''
(
set -x
# `foo_symlink` should be a symlink pointing to `foo_in_store`
[[ -L ${foo_symlink} ]]
[[ $(readlink ${foo_symlink}) == ${foo_in_store} ]]
# `symlink_to_not_in_store` should be a symlink pointing to `./.`, which
# is not available in the sandbox
[[ -L ${symlink_to_not_in_store} ]]
[[ $(readlink ${symlink_to_not_in_store}) == ${builtins.toString ./.} ]]
(! ls ${symlink_to_not_in_store}/)
# Native paths
)
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 ]]
# `foo_symlink` should be a symlink pointing to `foo_in_store`
[[ -L ${foo_symlink} ]]
[[ $(readlink ${foo_symlink}) == ${foo_in_store} ]]
# /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) ]]
)
# `symlink_to_not_in_store` should be a symlink pointing to `./.`, which
# is not available in the sandbox
[[ -L ${symlink_to_not_in_store} ]]
[[ $(readlink ${symlink_to_not_in_store}) == ${builtins.toString ./.} ]]
(! ls ${symlink_to_not_in_store}/)
)
echo "Success!" > $out
'';
touch $out
'';
};
}

0 comments on commit acbb152

Please sign in to comment.