From 0778b861a93eb47850ad8f48cfc4153bf31deba6 Mon Sep 17 00:00:00 2001 From: Sergei Zimmerman Date: Wed, 26 Nov 2025 03:47:42 +0300 Subject: [PATCH] libutil: Use openFileEnsureBeneathNoSymlinks in RestoreSink::createRegularFile Add more assertions for preconditions of openFileEnsureBeneathNoSymlinks to prevent misuse. Also start using it for regular file creation as well. --- src/libutil-tests/file-system.cc | 4 ++++ src/libutil/fs-sink.cc | 2 +- src/libutil/include/nix/util/file-descriptor.hh | 2 ++ src/libutil/unix/file-descriptor.cc | 3 +++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/libutil-tests/file-system.cc b/src/libutil-tests/file-system.cc index 3a54ac55b..8ea081c51 100644 --- a/src/libutil-tests/file-system.cc +++ b/src/libutil-tests/file-system.cc @@ -351,6 +351,10 @@ TEST(openFileEnsureBeneathNoSymlinks, works) sink.createDirectory( CanonPath("a/b/c/f"), [](FileSystemObjectSink & dirSink, const CanonPath & relPath) {}), SymlinkNotAllowed); + ASSERT_THROW( + sink.createRegularFile( + CanonPath("a/b/c/regular"), [](CreateRegularFileSink & crf) { crf("some contents"); }), + SymlinkNotAllowed); } AutoCloseFD dirFd = openDirectory(tmpDir); diff --git a/src/libutil/fs-sink.cc b/src/libutil/fs-sink.cc index 87bdaa339..521a10c9a 100644 --- a/src/libutil/fs-sink.cc +++ b/src/libutil/fs-sink.cc @@ -170,7 +170,7 @@ void RestoreSink::createRegularFile(const CanonPath & path, std::function= 1); auto components = std::views::take(path, nrComponents - 1); /* Everything but last component */ auto getParentFd = [&]() { return parentFd ? parentFd.get() : dirFd; }; @@ -320,6 +321,8 @@ openFileEnsureBeneathNoSymlinksIterative(Descriptor dirFd, const CanonPath & pat Descriptor unix::openFileEnsureBeneathNoSymlinks(Descriptor dirFd, const CanonPath & path, int flags, mode_t mode) { + assert(!path.rel().starts_with('/')); /* Just in case the invariant is somehow broken. */ + assert(!path.isRoot()); #ifdef __linux__ auto maybeFd = linux::openat2( dirFd, path.rel_c_str(), flags, static_cast(mode), RESOLVE_BENEATH | RESOLVE_NO_SYMLINKS);