From 1df3d8c79d5b070471a5a06dfaef2cc80081dd56 Mon Sep 17 00:00:00 2001 From: Emily Date: Sun, 10 Nov 2024 09:37:26 +0000 Subject: [PATCH] =?UTF-8?q?libutil:=20use=20OS=E2=80=90provided=20entropy?= =?UTF-8?q?=20for=20temporary=20filenames?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Relax the constraints on keeping the exact same filename format to provide a more robust source of entropy with a simpler interface (as previously suggested by eldritch horrors). Using 128 bits of OS‐provided entropy ensures global uniqueness and allows us to skip any thought of gracefully handling the case where these files already exist. My microbenchmark that repeatedly constructed paths like this and printed them out showed that this takes about 1.23× the time of the previous implementation, both taking on the order of a couple microseconds for one iteration. Since everything that uses it is doing things more expensive than printing to standard output, the actual performance delta is likely to be lost in the noise. If it somehow becomes a bottleneck, it can be optimized without sacrificing the guarantees by reading from the system RNG only to seed a thread‐local CSPRNG like [ChaCha8Rand], but I think that’s very unlikely. We also tweak the recommended way of creating a temporary file inside a directory in anticipation of later changes, and rename the `suffix` parameter to `prefix` (it’s a prefix to the random characters and a suffix to the root, but this way is more consistent). [ChaCha8Rand]: https://c2sp.org/chacha8rand Change-Id: I6a6a69648502c746d13d8c3bd2768cbbf1b90466 --- lix/libutil/file-system.cc | 13 +++++++++---- lix/libutil/file-system.hh | 8 ++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lix/libutil/file-system.cc b/lix/libutil/file-system.cc index 806190316..bdfadca80 100644 --- a/lix/libutil/file-system.cc +++ b/lix/libutil/file-system.cc @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "lix/libutil/environment-variables.hh" #include "lix/libutil/file-descriptor.hh" @@ -682,11 +684,14 @@ Path createTempSubdir(const Path & parent, const Path & prefix, } } -Path makeTempPath(const Path & root, const Path & suffix) +Path makeTempPath(const Path & root, const Path & prefix) { - // start the counter at a random value to minimize issues with preexisting temp paths - static std::atomic_uint_fast32_t counter(std::random_device{}()); - return fmt("%1%%2%-%3%-%4%", root, suffix, getpid(), counter.fetch_add(1, std::memory_order_relaxed)); + static thread_local std::random_device generator{}; + std::uniform_int_distribution uniform_dist{}; + const uint64_t entropy[2] = {uniform_dist(generator), uniform_dist(generator)}; + auto unique = base32Encode(std::as_bytes(std::span(entropy))); + + return fmt("%s%s-%s", root, prefix, unique); } Path makeTempSiblingPath(const Path & path) diff --git a/lix/libutil/file-system.hh b/lix/libutil/file-system.hh index 16f4d0518..f644acae3 100644 --- a/lix/libutil/file-system.hh +++ b/lix/libutil/file-system.hh @@ -305,12 +305,12 @@ Path createTempSubdir(const Path & parent, const Path & prefix = "nix", bool includePid = true, bool useGlobalCounter = true, mode_t mode = 0755); /** - * Return temporary path constructed by appending a suffix to a root path. + * Return temporary path constructed by appending to a root path. * - * The constructed path looks like `--`. To create a - * path nested in a directory, provide a suffix starting with `/`. + * The constructed path looks like `-`. To create a + * path nested in a directory, provide a root ending with `/`. */ -Path makeTempPath(const Path & root, const Path & suffix = ".tmp"); +Path makeTempPath(const Path & root, const Path & prefix = ".tmp"); /** * Return temporary path in the same directory as a given path.