From ef94901156c0c688ffffaa2c5caf1498119f01d4 Mon Sep 17 00:00:00 2001 From: Raito Bezarius Date: Sat, 26 Jul 2025 01:11:58 +0200 Subject: [PATCH] libstore/build: `pathContentsGood` is physical path aware now `pathContentsGood` is used to assess the validity of a path as part of derivation goals *in repair mode*. When repair is used with a diverted store, i.e. a store where fsPath(toRealPath(s)) != fsPath(s) for s a store path, this result in utterly broken behavior because it will attempt to assess the goodness of the *logical* store locations, most of the time: /nix/store/... So, if you are repairing your system using a live NixOS ISO. Your ISO contains a `/nix/store` (assumed to be good) and you repair your system which is rooted at /mnt and contains its own /nix/store, that is, a Nix store at /mnt/nix/store. Performing the following operation `nix-store --verify --repair --store /mnt` will assess the contents goodness of the ISO's Nix store. To avoid this, we assess the path existence of the *physical path*, aka the result of `store.toRealPath` applied to a *logical* store path string representation and we verify the hash of the *physical path*. The error messages are not taken care of in this CL as those are purely cosmetic and helps the user understand what is going on. Fixes #892. Change-Id: Ib9e0153cb5683edcf37f1963ebf065ceba5e5dfb Signed-off-by: Raito Bezarius --- lix/libstore/build/worker.cc | 7 +++--- tests/functional/meson.build | 1 + tests/functional/repair-chroot.sh | 36 +++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 tests/functional/repair-chroot.sh diff --git a/lix/libstore/build/worker.cc b/lix/libstore/build/worker.cc index 786919912..6a5827516 100644 --- a/lix/libstore/build/worker.cc +++ b/lix/libstore/build/worker.cc @@ -389,10 +389,11 @@ try { printInfo("checking path '%s'...", store.toRealPath(store.printStorePath(path))); auto info = TRY_AWAIT(store.queryPathInfo(path)); bool res; - if (!pathExists(store.printStorePath(path))) + if (!pathExists(store.toRealPath(store.printStorePath(path)))) { res = false; - else { - HashResult current = hashPath(info->narHash.type, store.printStorePath(path)); + } else { + HashResult current = + hashPath(info->narHash.type, store.toRealPath(store.printStorePath(path))); Hash nullHash(HashType::SHA256); res = info->narHash == nullHash || info->narHash == current.first; } diff --git a/tests/functional/meson.build b/tests/functional/meson.build index eb1976430..aac8da747 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -67,6 +67,7 @@ functional_tests_scripts = [ 'nix-build.sh', 'gc-concurrent.sh', 'repair.sh', + 'repair-chroot.sh', 'fixed.sh', 'export-graph.sh', 'timeout.sh', diff --git a/tests/functional/repair-chroot.sh b/tests/functional/repair-chroot.sh new file mode 100644 index 000000000..150c73a9b --- /dev/null +++ b/tests/functional/repair-chroot.sh @@ -0,0 +1,36 @@ +source common.sh + +if [[ $(uname) == Darwin ]]; then skipTest "Darwin does not have diverted stores"; fi +needLocalStore "--repair needs a local store" + +clearStore + +path=$(nix-build dependencies.nix -o $TEST_ROOT/result) +path2=$(nix-store -qR $path | grep input-2) +path2_basename=$(basename $path2) + +# Corrupt a path in a *chroot* store and check whether nix-build --repair can fix it. +extra_chroot_store_path="$TEST_ROOT/extra-chroot-store" +# Required because otherwise storeDir=/build/... in the sandbox. +special_sandbox_build_dir="/build-tmp" +chroot_path=$(nix-build dependencies.nix -o $TEST_ROOT/chroot-result --sandbox-build-dir "$special_sandbox_build_dir" --store "$extra_chroot_store_path" --extra-sandbox-paths /nix/store) +chroot_path2="$extra_chroot_store_path/nix/store/$path2_basename" + +[ -d $chroot_path2 ] || fail "chroot path $chroot_path2 does not exist" + +nix-store --verify --check-contents --sandbox-build-dir "$special_sandbox_build_dir" -v --store "$extra_chroot_store_path" |& grepQuiet "$extra_chroot_store_path" || fail "$extra_chroot_store_path does not occur in the store verification, the chroot store parameter is ignored." +chroot_hash=$(nix-hash $path2) + +chmod u+w $chroot_path2 +touch $chroot_path2/bad + +! nix-store --verify --check-contents -v --store "$extra_chroot_store_path" --sandbox-build-dir "$special_sandbox_build_dir" + +# The path can be repaired by rebuilding the derivation. +nix-store --verify --check-contents --repair --store "$extra_chroot_store_path" --extra-sandbox-paths /nix/store --sandbox-build-dir "$special_sandbox_build_dir" + +! [ -e $chroot_path2/bad ] +! [ -w $chroot_path2 ] + +# NOTE: verify path must be given the *LOGICAL* path here. And not the physical path. Confusing? I know. +nix-store --verify-path $path2 --store "$extra_chroot_store_path"