Skip to content

Commit 1cc79f1

Browse files
Théophane Hufschmittroberth
authored andcommitted
Fix the access of symlinks to host files in the sandbox
#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. (cherry picked from commit acbb152)
1 parent 8d763e7 commit 1cc79f1

3 files changed

Lines changed: 62 additions & 20 deletions

File tree

src/libstore/build/local-derivation-goal.cc

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,11 +1847,18 @@ void LocalDerivationGoal::runChild()
18471847
if (pathExists(path))
18481848
ss.push_back(path);
18491849

1850-
if (settings.caFile != "")
1851-
pathsInChroot.try_emplace("/etc/ssl/certs/ca-certificates.crt", settings.caFile, true);
1850+
if (settings.caFile != "" && pathExists(settings.caFile)) {
1851+
Path caFile = settings.caFile;
1852+
pathsInChroot.try_emplace("/etc/ssl/certs/ca-certificates.crt", canonPath(caFile, true), true);
1853+
}
18521854
}
18531855

1854-
for (auto & i : ss) pathsInChroot.emplace(i, i);
1856+
for (auto & i : ss) {
1857+
// For backwards-compatibiliy, resolve all the symlinks in the
1858+
// chroot paths
1859+
auto canonicalPath = canonPath(i, true);
1860+
pathsInChroot.emplace(i, canonicalPath);
1861+
}
18551862

18561863
/* Bind-mount all the directories from the "host"
18571864
filesystem that we want in the chroot

tests/functional/linux-sandbox.sh

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ testCert () {
6060

6161
nocert=$TEST_ROOT/no-cert-file.pem
6262
cert=$TEST_ROOT/some-cert-file.pem
63+
symlinkcert=$TEST_ROOT/symlink-cert-file.pem
64+
symlinkDir=$TEST_ROOT/symlink-dir
6365
echo -n "CERT_CONTENT" > $cert
66+
ln -s $cert $symlinkcert
67+
ln -s $TEST_ROOT $symlinkDir
6468

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

81+
# Cert in sandbox when ssl-cert-file is set to a symlink to an existing file
82+
testCert present fixed-output "$symlinkcert"
83+
7784
# Symlinks should be added in the sandbox directly and not followed
78-
nix-sandbox-build symlink-derivation.nix
85+
nix-sandbox-build symlink-derivation.nix -A depends_on_symlink
86+
nix-sandbox-build symlink-derivation.nix -A test_sandbox_paths \
87+
--option extra-sandbox-paths "/file=$cert" \
88+
--option extra-sandbox-paths "/dir=$TEST_ROOT" \
89+
--option extra-sandbox-paths "/symlinkDir=$symlinkDir" \
90+
--option extra-sandbox-paths "/symlink=$symlinkcert"

tests/functional/symlink-derivation.nix

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,45 @@ let
1515
'';
1616
};
1717
in
18-
mkDerivation {
19-
name = "depends-on-symlink";
20-
buildCommand = ''
21-
(
22-
set -x
18+
{
19+
depends_on_symlink = mkDerivation {
20+
name = "depends-on-symlink";
21+
buildCommand = ''
22+
(
23+
set -x
24+
25+
# `foo_symlink` should be a symlink pointing to `foo_in_store`
26+
[[ -L ${foo_symlink} ]]
27+
[[ $(readlink ${foo_symlink}) == ${foo_in_store} ]]
28+
29+
# `symlink_to_not_in_store` should be a symlink pointing to `./.`, which
30+
# is not available in the sandbox
31+
[[ -L ${symlink_to_not_in_store} ]]
32+
[[ $(readlink ${symlink_to_not_in_store}) == ${builtins.toString ./.} ]]
33+
(! ls ${symlink_to_not_in_store}/)
34+
35+
# Native paths
36+
)
37+
echo "Success!" > $out
38+
'';
39+
};
40+
41+
test_sandbox_paths = mkDerivation {
42+
# Depends on the caller to set a bunch of `--sandbox-path` arguments
43+
name = "test-sandbox-paths";
44+
buildCommand = ''
45+
(
46+
set -x
47+
[[ -f /file ]]
48+
[[ -d /dir ]]
2349
24-
# `foo_symlink` should be a symlink pointing to `foo_in_store`
25-
[[ -L ${foo_symlink} ]]
26-
[[ $(readlink ${foo_symlink}) == ${foo_in_store} ]]
50+
# /symlink and /symlinkDir should be available as raw symlinks
51+
# (pointing to files outside of the sandbox)
52+
[[ -L /symlink ]] && [[ ! -e $(readlink /symlink) ]]
53+
[[ -L /symlinkDir ]] && [[ ! -e $(readlink /symlinkDir) ]]
54+
)
2755
28-
# `symlink_to_not_in_store` should be a symlink pointing to `./.`, which
29-
# is not available in the sandbox
30-
[[ -L ${symlink_to_not_in_store} ]]
31-
[[ $(readlink ${symlink_to_not_in_store}) == ${builtins.toString ./.} ]]
32-
(! ls ${symlink_to_not_in_store}/)
33-
)
34-
echo "Success!" > $out
35-
'';
56+
touch $out
57+
'';
58+
};
3659
}

0 commit comments

Comments
 (0)