From 5ec91381795ffd4df4a12ba3ca6febb37129f66e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 29 Sep 2025 12:21:57 +0200 Subject: [PATCH] Prevent infinite symlink loop in followLinksToStore() The followLinksToStore() function could hang indefinitely when encountering symlink cycles outside the Nix store, causing 100% CPU usage and blocking any operations that use this function. This affects multiple commands including nix-store --query, --delete, --verify, nix-env, and nix-copy-closure when given paths with symlink cycles. The fix adds a maximum limit of 1024 symlink follows (matching the limit used by canonPath) and throws an error when exceeded, preventing the infinite loop while preserving the original semantics of stopping at the first path inside the store. --- src/libstore/store-api.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index a0b06db54..c26c7d826 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -58,12 +58,22 @@ std::pair StoreDirConfig::toStorePath(PathView path) const Path Store::followLinksToStore(std::string_view _path) const { Path path = absPath(std::string(_path)); + + // Limit symlink follows to prevent infinite loops + unsigned int followCount = 0; + const unsigned int maxFollow = 1024; + while (!isInStore(path)) { if (!std::filesystem::is_symlink(path)) break; + + if (++followCount >= maxFollow) + throw Error("too many symbolic links encountered while resolving '%s'", _path); + auto target = readLink(path); path = absPath(target, dirOf(path)); } + if (!isInStore(path)) throw BadStorePath("path '%1%' is not in the Nix store", path); return path;