summaryrefslogtreecommitdiff
path: root/nix/libutil
AgeCommit message (Collapse)AuthorFilesLines
2026-08-17daemon: Bypass authentication when importing content-addressed store items.Ludovic Courtès2-0/+10
This puts ‘importPaths’ on par with ‘addToStore’ and ‘addTextToStore’: since the two latter RPCs let anyone add content-addressed items in the store, there’s no reason for ‘importPaths’ to require signatures by authorized keys on these content-addressed items. This will allow for things like ‘guix copy’ of .drv items without authorization, or ‘guix deploy’ with (build-locally? #f) without authorization. * nix/libstore/store-api.hh (isContentAddressedPath): New prototype. * nix/libstore/store-api.cc (isContentAddressedPath): New function. * nix/libutil/util.hh (isPlainFile): New prototype. * nix/libutil/util.cc (isPlainFile): New function. * nix/libstore/local-store.cc (LocalStore::importPath): Define ‘narHash’ and ‘contentAddressed’. Allow unsigned imports when ‘contentAddressed’ is true; bypass signature verification when ‘contentAddressed’ is true. * tests/store.scm ("import not signed"): Rewrite to not use a content-addressed store item. ("import signed by unauthorized key"): Likewise. ("import not signed but content-addressed tree"): New test. ("import not signed but content-addressed regular file"): New test. ("import signed by unauthorized key but content-addressed"): New test. ("import with corrupt signature"): New test. ("import signed by authorized key but hash doesn't match"): New test. ("import with corrupt signature but content-addressed"): New test. ("import signed by authorized key, hash doesn't match, but content-addressed"): New test. * doc/guix.texi (Invoking guix archive): Document the exception for content-addressed store items. Add anchor for ‘--authorize’. (Invoking guix deploy): Document the benefit of (build-locally? #f). Add cross-reference for ‘authorize?’. Co-authored-by: Reepca Russelstein <reepca@russelstein.xyz> Signed-off-by: Ludovic Courtès <ludo@gnu.org> Merges: #8979
2026-07-02daemon: libutil: make nar parser much stricter.Reepca Russelstein1-56/+136
The prior implementation of 'parse' was, to put it mildly, very accepting of invalid input. This made it very difficult to review its security properties, which ended up relying entirely on the fact that it still didn't allow "/" in directory entry names and that O_CREAT|O_EXCL implicitly causes symlinks to not be followed in the final component, and mkdir and symlink never follow symlinks in the final component, and all of the above throw exceptions when they fail. Some examples of what was allowed prior: 1. Empty archives: "nix-archive-1" "(" ")" 2. Archives with only a type: "nix-archive-1" "(" "type" "regular" ")" 3. Archives of regular files with multiple contents, which would be concatenated (e.g. this has contents "foobar"): "nix-archive-1" "(" "type" "regular" "contents" "foo" "contents" "bar" ")" 4. Archives of directories with multiple entries with the same name, and that aren't sorted: "nix-archive-1" "(" "type" "directory" "entry" "(" "name" "c" "node" "(" ")" ")" "entry" "(" "name" "b" "node" "(" ")" ")" "entry" "(" "name" "b" "node" "(" ")" ")" "entry" "(" "name" "a" "node" "(" ")" ")" ")" 5. Archives of directories with empty entries: "nix-archive-1" "(" "type" "directory" "entry" "(" ")" ")" 6. Archives of directories with entries with no name: "nix-archive-1" "(" "type" "directory" "entry" "(" "node" "(" ")" ")" ")" 7. Archives of directories with entries with no node: "nix-archive-1" "(" "type" "directory" "entry" "(" "name" "a" ")" ")" 7. Archives of directories with entries with multiple names: "nix-archive-1" "(" "type" "directory" "entry" "(" "name" "a" "node" "(" ")" "name" "b" ")" ")" 8. Archives of directories with entries with multiple nodes: "nix-archive-1" "(" "type" "directory" "entry" "(" "node" "(" ")" "node" "(" ")" ")" ")" 9. Archives of directories with entries with multiple names and multiple nodes: "nix-archive-1" "(" "type" "directory" "entry" "(" "name" "a" "node" "(" ")" "name" "b" "node" "(" ")" ")" ")" Such permissiveness rather defeats the "normalized" part of "Normalized ARchive". Additionally, 'parse' previously used recursion with no explicit depth limit. In practice Linux would still limit the depth to around 2048, since filenames longer than 4096 bytes yield ENAMETOOLONG, but no such restriction exists on Hurd. The permissiveness issue is resolved by rewriting 'parse', and the unbounded recursion issue is resolved by adding a nestLimit parameter so that no more than DIRECTORY_NESTING_LIMIT (currently 256) levels of recursion are used. An alternate implementation that doesn't use recursion, 'parse_unbounded', is included in case it is determined that the nesting limit should be removed, but currently only 'parse' is used. * nix/libutil/archive.cc (parse): rewrite to add nestLimit parameter. (parseDump): pass DIRECTORY_NESTING_LIMIT as nestLimit argument to 'parse'. (parse_unbounded): new function. Change-Id: Ia3c32cc645b609f6ae7f3bcafc491ec0073cbb51 Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2026-06-24daemon: libutil: add isHash32.Reepca Russelstein2-1/+15
* nix/libutil/hash.hh (isHash32): new function. * nix/libutil/hash.hh (isHash32): provide implementation. Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2026-06-24daemon: libutil: add base32Values and use them.Reepca Russelstein2-4/+18
Recognizing base32 characters and/or parsing them into byte sequences is done in several places, so it makes sense to provide a common lookup table. * nix/libutil/hash.hh (base32Values, base32ValuesInitialized): new variables. (initializeBase32Values, getBase32Value): new functions. * nix/libutil/hash.cc (base32Values, base32ValuesInitialized): provide definition for variables. (initializeBase32Values, getBase32Value): provide function implementations. (parseHash32): use base32Values. * nix/libstore/references.cc (search): use base32Values. Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2026-02-27daemon: Actually remove unreadable directories.Reepca Russelstein2-3/+57
Fixes a regression introduced in 7173c2c0ca. Additional discussion at https://codeberg.org/guix/guix/pulls/5977. * nix/libutil/util.cc (_deletePathAt): chmod directory and retry open when it fails with EACCES. Do this using an O_PATH file descriptor referenced via /proc/self/fd whenever possible to avoid it being replaced by a non-directory immediately before being chmod'ed. * nix/libutil/util.hh (deletePath): document TOCTTOU race on non-linux systems where hardlinks aren't protected. * tests/derivations.scm ("unreadable directories in build tree can be removed"): new test. Fixes: guix/guix#5891 Reported-by: Liliana Marie Prikler <liliana.prikler@gmail.com> Change-Id: I749127fe5254ebabc8387a2f0ef47e3c116bfcc5 Signed-off-by: Ludovic Courtès <ludo@gnu.org> Merges: #6460
2026-01-22Merge branch 'version-1.5.0'Rutherther1-1/+1
Change-Id: Id73c0c74600a3da3373b3a37236b505af65bfe31
2026-01-14nix: Spelling corrections.Efraim Flashner1-1/+1
* nix/libstore/globals.hh, nix/libstore/store-api.hh, nix/libutil/util.hh: Fix misspellings in comments. Change-Id: Id77ea2bde1c2582d1a7bec4ed256ea900998c4b8
2026-01-12daemon: Fix several format strings.Ludovic Courtès1-1/+1
This is a followup to 3af52f845fe2ceb448416ac7b9f48925673c594e and 6f1448ef89c8ad29e2a479099531fd3a87701e46. * nix/libstore/local-store.cc (LocalStore::queryValidPathId): Change %1% to {}. * nix/libstore/optimise-store.cc (LocalStore::optimisePath_): Likewise. * nix/nix-daemon/guix-daemon.cc (open_unix_domain_socket): Likewise. (main): Likewise. * nix/libutil/affinity.cc (restoreAffinity): Remove useless %1%. Change-Id: I3a7cd79cd69ab58f14118662f1dcf2fef067a6b7
2025-11-12daemon: Use inline functions and variables instead of externCongcong Kuo6-22/+8
Avoid separate declarations and definitions for so-called 'global' objects. * nix/libstore/derivations.{cc, hh} (drvHashes): Use inline instead of separate declaration and definition. * nix/libstore/globals.{cc, hh} (settings, nixVersion): Same. * nix/libstore/local-store.hh (drvsLogDir, deduplicationMinSize): Same. * nix/libstore/optimise-store.cc (deduplicationMinSize): Same. * nix/libstore/store-api.{cc, hh} (store): Same. * nix/libutil/archive.{cc, hh} (defaultPathFilter): Same. * nix/libutil/hash.{cc, hh} (base32Chars): Same and modify header files. * nix/libutil/util.{cc, hh} (logType, verbosity, _writeToStderr, _isInterrupted): Same. * nix/local.mk: Modified according to the rename of shared.hh. * nix/nix-daemon/guix-daemon.cc (blockInt, argvSaved, run): Same and modify header files. * nix/nix-daemon/nix-daemon.cc: Modify header files. * nix/nix-daemon/shared.hh: Renamed to nix-daemon.hh Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2025-11-03daemon: Use starts_with() and ends_with() instead of string() or hasSuffix()Congcong Kuo5-15/+1
* nix/libstore/build.cc (DerivationGoal::tryBuildHook): Use starts_with instead of string() * nix/libstore/builtins.cc (lookupBuiltinBuilder): Same. * nix/libstore/builtins.hh (isBuiltin): Same and fix indentation of the file. * nix/libstore/derivations.cc (DerivationOutput::parseHashInfo, isDerivation): Same and clean header files. * nix/libstore/gc.cc (addPermRoot, LocalStore::isActiveTempFile): Same. * nix/libstore/globals.cc: Same. * nix/libstore/local-store.cc: Same. * nix/libstore/misc.cc: Same. * nix/libstore/store-api.cc (checkStoreName): Same. * nix/libutil/affinity.cc: Same. * nix/libutil/archive.cc: Same. * nix/libutil/spawn.cc: Same. * nix/libutil/util.{cc, hh} (hasSuffix): Removed. Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2025-10-19daemon: Bump to C++20 and use ‘std::format’ instead of ‘boost::format’.Congcong Kuo9-152/+159
* nix/boost: This directory and all files inside it are removed. * nix/libstore/build.cc (Goal::trace): Use ‘std::string’ instead of ‘const format &’. (DerivationGoal::startBuilder, ...): Use ‘std::format’ or ‘std::vformat’ instead of ‘boost::format’. * nix/libstore/builtins.cc (builtinDownload): Same. * nix/libstore/derivations.cc (DerivationOutput::parseHashInfo, ...): Same. * nix/libstore/gc.cc (LocalStore::openGCLock, ...): Same. * nix/libstore/globals.cc (Settings::_get): Same. * nix/libstore/local-store.cc: (checkStoreNotSymlink, ...): Same. * nix/libstore/misc.cc (dfsVisit, showBytes): Same * nix/libstore/optimise-store.cc (makeWritable, ...): Same. * nix/libstore/pathlocks.cc (openLockFile, ...): Same. * nix/libstore/references.cc (search, scanForReferences): Same. * nix/libstore/sqlite.hh (throwSQLiteError): Use ‘std::string’ instead of ‘const format &’. * nix/libstore/sqlite.cc (throwSQLiteError): Use ‘std::string’ instead of ‘const format &’. * nix/libstore/store-api.cc (assertStorePath, ...): Use ‘std::format’ instead of ‘boost::format’. * nix/libutil/affinity.cc (setAffinityTo): Same. * nix/libutil/archive.cc (dumpContents, ...): Same. * nix/libutil/hash.cc (parseHash, parseHash32, parseHash16or32, hashFile): Same. * nix/libutil/hash.hh (parseHash, parseHash32, parseHash16or32, isHash): Same. * nix/libutil/serialise.cc : Add ‘<cassert>’ header file. * nix/libutil/spawn.cc (addPhaseAfter, ...): Use ‘std::format’ instead of ‘boost::format’. * nix/libutil/types.hh (FormatOrString): Removed. (BaseError, BaseError::addPrefix, SysError, MakeError): Use ‘std::string or std::string_view’ instead of ‘FormatOrString’. * nix/libutil/util.hh (Nest::open, printMsg_, warnOnce, expect): Same. * nix/libutil/util.cc (BaseError::BaseError, ...): Same. (writeToStderr, _interrupted): Use std::uncaught_exceptions() instead of std::uncaught_exception() * nix/nix-daemon/nix-daemon.cc (performOp, ...): Same. * nix/nix-daemon/guix-daemon.cc (string_to_bool, ...): Same. * nix/local.mk: Remove ‘libformat.a’ from ‘noinst_LIBRARIES’, remove ‘libformat_a_SOURCES’ and ‘libformat_headers’, remove ‘libformat_a_CPPFLAGS’ from ‘libutil_a_CPPFLAGS’ and ‘guix_daemon_LDADD’, update ‘AM_CXXFLAGS’ to ‘-std=c++20’. Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2025-10-16daemon: Export as little as needed from libutil/spawn.cc.Ludovic Courtès2-76/+37
* nix/libutil/spawn.cc (reset_writeToStderrAction, restoreAffinityAction) (setsidAction, earlyIOSetupAction, dropAmbientCapabilitiesAction) (chrootAction, chdirAction, closeMostFDsAction, setPersonalityAction) (oomSacrificeAction, setIDsAction, setNoNewPrivsAction) (addSeccompFilterAction, restoreSIGPIPEAction, setupSuccessAction) (usernsInitSyncAction, usernsSetIDsAction, initLoopbackAction) (setHostAndDomainAction, makeFilesystemsPrivateAction) (makeChrootSeparateFilesystemAction, bindMount) (mountIntoChroot, mountIntoChrootAction, mountProcAction) (mountDevshmAction, mountDevptsAction, pivotRootAction) (idMapToIdentityMap, lockMountsAction, runChildSetupEntry): Add ‘static’ qualifier. * nix/libutil/spawn.hh: Remove the corresponding ‘extern’ declarations. Change-Id: I3156d72d866f22fa31aa9a843f116771763ccb61
2025-10-16daemon: ‘runProgram’ exits with 127 upon ENOENT or similar.Ludovic Courtès1-1/+3
This is in accordance with widespread conventions. Previously it would exit with code 1, which was misleading. * nix/libutil/util.cc (runProgram): Exit with 127 if ‘execv’ or ‘execvp’ fails. Change-Id: I5df214afffda69aa329a25afbc48f6cbfdd0961c
2025-07-16daemon: Use std::string or std::vector instead of variable-length array (VLA).Congcong Kuo3-17/+16
* libutil/util.h (waitForMessage): Use std::string instead of char* to unify coding style. * libutil/util.cc (waitForMessage): Use std::string instead of variable-length array (VLA). (readLink, copyFileRecursively, expect): Use std::vector instead of VLA. * libutil/hash.cc (printHash): Use std::vector instead of VLA. Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2025-07-04daemon: Gracefully handle target mount point already existing.Reepca Russelstein1-1/+24
Fixes guix/guix#903. * nix/libutil/spawn.cc (bindMount): in the "regular file" case, only create a placeholder file if one doesn't already exist. Change-Id: Ie46b2fef2cea5b2a052c4ec48d00e97bfc1ee506 Reported-by: Hilton Chain <hako@ultrarare.space> Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2025-06-26daemon: Fix build of spawn.cc for non-Linux and newer GCC.Reepca Russelstein1-0/+7
* nix/libutil/spawn.cc: Include <fcntl.h> and <cstdint>. (cloneChild): Wrap body in #if CLONE_ENABLED. Change-Id: I0be7e6dbe80ac2f7022793149472270a4e49d23c Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2025-06-25daemon: Fix build with gcc-14.Andreas Enge1-0/+1
* nix/libutil/seccomp.hh: Include cstdint. Change-Id: I454c7abd56abbe4cf03a5bc8ebc402678e07a0f0
2025-06-24daemon: Protect ‘copyFileRecursively’ from race conditions.Ludovic Courtès1-3/+5
Previously, if an attacker managed to introduce a hard link or a symlink on one of the destination file names before it is opened, ‘copyFileRecursively’ would overwrite the symlink’s target or the hard link’s content. This kind of attack could be carried out while guix-daemon is copying the output or the chroot directory of a failed fixed-output derivation build, possibly allowing the attacker to escalate to the privileges of the build user. * nix/libutil/util.cc (copyFileRecursively): In the ‘S_ISREG’ case, open ‘destination’ with O_NOFOLLOW | O_EXCL. In the ‘S_ISDIR’ case, open ‘destination’ with O_NOFOLLOW. Reported-by: Reepca Russelstein <reepca@russelstein.xyz> Change-Id: I94273efe4e92c1a4270a98c5ec47bd098e9227c9 Signed-off-by: John Kehayias <john.kehayias@protonmail.com>
2025-06-24daemon: add seccomp filter for slirp4netns.Reepca Russelstein4-0/+430
The container that slirp4netns runs in should already be quite difficult to do anything malicious in beyond basic denial of service or sending of network traffic. There is, however, one hole remaining in the case in which there is an adversary able to run code locally: abstract unix sockets. Because these are governed by network namespaces, not IPC namespaces, and slirp4netns is in the root network namespace, any process in the root network namespace can cooperate with the slirp4netns process to take over its user. To close this, we use seccomp to block the creation of unix-domain sockets by slirp4netns. This requires some finesse, since slirp4netns absolutely needs to be able to create other types of sockets - at minimum AF_INET and AF_INET6 Seccomp has many, many pitfalls. To name a few: 1. Seccomp provides you with an "arch" field, but this does not uniquely determine the ABI being used; the actual meaning of a system call number depends on both the number (which is often the result of ORing a related system call with a flag for an alternate ABI) and the architecture. 2. Seccomp provides no direct way of knowing what the native value for the arch field should be; the user must do configure/compile-time testing for every architecture+ABI combination they want to support. Amusingly enough, the linux-internal header files have this exact information (SECCOMP_ARCH_NATIVE), but they aren't sharing it. 3. The only system call numbers we naturally have are the native ones in asm/unistd.h. __NR_socket will always refer to the system call number for the target system's ABI. 4. Seccomp can only manipulate 32-bit words, but represents every system call argument as a uint64. 5. New system call numbers with as-yet-unknown semantics can be added to the kernel at any time. 6. Based on this comment in arch/x86/entry/syscalls/syscall_32.tbl: # 251 is available for reuse (was briefly sys_set_zone_reclaim) previously-invalid system call numbers may later be reused for new system calls. 7. Most architecture+ABI combinations have system call tables with many gaps in them. arm-eabi, for example, has 35 such gaps (note: this is just the number of distinct gaps, not the number of system call numbers contained in those gaps). 8. Seccomp's BPF filters require a fully-acyclic control flow graph. Any operation on a data structure must therefore first be fully unrolled before it can be run. 9. Seccomp cannot dereference pointers. Only the raw bits provided to the system calls can be inspected. 10. Some architecture+ABI combos have multiplexer system calls. For example, socketcall can perform any socket-related system call. The arguments to the multiplexed system call are passed indirectly, via a pointer to user memory. They therefore cannot be inspected by seccomp. 11. Some valid system calls are not listed in any table in the kernel source. For example, __ARM_NR_cacheflush is an "ARM private" system call. It does not appear in any *.tbl file. 12. Conditional branches are limited to relative jumps of at most 256 instructions forward. 13. Prior to Linux 4.8, any process able to spawn another process and call ptrace could bypass seccomp restrictions. To address (1), (2), and (3), we include preprocessor checks to identify the native architecture value, and reject all system calls that don't use the native architecture. To address (4), we use the AC_C_BIGENDIAN autoconf check to conditionally define WORDS_BIGENDIAN, and match up the proper portions of any uint64 we test for with the value in the accumulator being tested against. To address (5) and (6), we use system call pinning. That is, we hardcode a snapshot of all the valid system call numbers at the time of writing, and reject any system call numbers not in the recorded set. A set is recorded for every architecture+ABI combo, and the native one is chosen at compile-time. This ensures that not only are non-native architectures rejected, but so are non-native ABIs. For the sake of conciseness, we represent these sets as sets of disjoint ranges. Due to (7), checking each range in turn could add a lot of overhead to each system call, so we instead binary search through the ranges. Due to (8), this binary search has to be fully unrolled, so we do that too. It can be tedious and error-prone to manually produce the syscall ranges by looking at linux's *.tbl files, since the gaps are often small and uncommented. To address this, a script, build-aux/extract-syscall-ranges.sh, is added that will produce them given a *.tbl filename and an ABI regex (some tables seem to abuse the ABI field with strange values like "memfd_secret"). Note that producing the final values still requires looking at the proper asm/unistd.h file to find any private numbers and to identify any offsets and ABI variants used. (10) used to have no good solution, but in the past decade most architectures have gained dedicated system call alternatives to at least socketcall, so we can (hopefully) just block it entirely. To address (13), we block ptrace also. * build-aux/extract-syscall-ranges.sh: new script. * Makefile.am (EXTRA_DIST): register it. * config-daemon.ac: use AC_C_BIGENDIAN. * nix/libutil/spawn.cc (setNoNewPrivsAction, addSeccompFilterAction): new functions. * nix/libutil/spawn.hh (setNoNewPrivsAction, addSeccompFilterAction): new declarations. (SpawnContext)[setNoNewPrivs, addSeccompFilter]: new fields. * nix/libutil/seccomp.hh: new header file. * nix/libutil/seccomp.cc: new file. * nix/local.mk (libutil_a_SOURCES, libutil_headers): register them. * nix/libstore/build.cc (slirpSeccompFilter, writeSeccompFilterDot): new functions. (spawnSlirp4netns): use them, set seccomp filter for slirp4netns. Change-Id: Ic92c7f564ab12596b87ed0801b22f88fbb543b95 Signed-off-by: John Kehayias <john.kehayias@protonmail.com>
2025-06-24daemon: Use slirp4netns to provide networking to fixed-output derivations.Reepca Russelstein2-0/+117
Previously, the builder of a fixed-output derivation could communicate with an external process via an abstract Unix-domain socket. In particular, it could send an open file descriptor to the store, granting write access to some of its output files in the store provided the derivation build fails—the fix for CVE-2024-27297 did not address this specific case. It could also send an open file descriptor to a setuid program, which could then be executed using execveat to gain the privileges of the build user. With this change, fixed-output derivations other than “builtin:download” and “builtin:git-download” always run in a separate network namespace and have network access provided by a TAP device backed by slirp4netns, thereby closing the abstract Unix-domain socket channel. * nix/libstore/globals.hh (Settings)[useHostLoopback, slirp4netns]: new fields. * config-daemon.ac (SLIRP4NETNS): new C preprocessor definition. * nix/libstore/globals.cc (Settings::Settings): initialize them to defaults. * nix/nix-daemon/guix-daemon.cc (options): add --isolate-host-loopback option. * doc/guix.texi: document it. * nix/libstore/build.cc (DerivationGoal)[slirp]: New field. (setupTap, setupTapAction, waitForSlirpReadyAction, enableRouteLocalnetAction, prepareSlirpChrootAction, spawnSlirp4netns, haveGlobalIPv6Address, remapIdsTo0Action): New functions. (initializeUserNamespace): allow the guest UID and GID to be specified. (DerivationGoal::killChild): When ‘slirp’ is not -1, call ‘kill’. (DerivationGoal::startBuilder): Unconditionally add CLONE_NEWNET to FLAGS. When ‘fixedOutput’ is true, spawn ‘slirp4netns’. When ‘fixedOutput’ and ‘useChroot’ are true, add setupTapAction, waitForSlirpReadyAction, and enableRouteLocalnetAction to builder setup phases. Create a /etc/resolv.conf for fixed-output derivations that directs them to slirp4netns's dns address. When settings.useHostLoopback is true, supply fixed-output derivations with a /etc/hosts that resolves "localhost" to slirp4netns's address for accessing the host loopback. * nix/libutil/util.cc (keepOnExec, decodeOctalEscaped, sendFD, receiveFD, findProgram): New functions. * nix/libutil/util.hh (keepOnExec, decodeOctalEscaped, sendFD, receiveFD, findProgram): New declarations. * gnu/packages/package-management.scm (guix): add slirp4netns input for linux targets. * tests/derivations.scm (builder-network-isolated?): new variable. ("fixed-output derivation, network access, localhost", "fixed-output derivation, network access, external host"): skip test case if fixed output derivations are isolated from the network. Change-Id: Ia3fea2ab7add56df66800071cf15cdafe7bfab96 Signed-off-by: John Kehayias <john.kehayias@protonmail.com>
2025-06-24daemon: add and use spawn.cc and spawn.hh.Reepca Russelstein4-0/+1017
This adds a mechanism for manipulating and running "spawn phases" similarly to how builder-side code manipulates "build phases". The main difference is that spawn phases take a (reference to a) single structure that they can both read from and write to, with their writes being visible to subsequent phases. The base structure type for this is SpawnContext. It also adds some predefined phase sequences, namely basicSpawnPhases and cloneSpawnPhases, and exposes each of the actions performed by these phases. Finally, it modifies build.cc to replace runChild() with use of this new code. * nix/libutil/util.cc (keepOnExec, waitForMessage): new functions. * nix/libutil.util.hh (keepOnExec, waitForMessage): add prototypes. * nix/libutil/spawn.cc, nix/libutil/spawn.hh: new files. (addPhaseAfter, addPhaseBefore, prependPhase, appendPhase, deletePhase, replacePhase, reset_writeToStderrAction, restoreAffinityAction, setsidAction, earlyIOSetupAction, dropAmbientCapabilitiesAction, chrootAction, chdirAction, closeMostFDsAction, setPersonalityAction, oomSacrificeAction, setIDsAction, restoreSIGPIPEAction, setupSuccessAction, execAction, getBasicSpawnPhases, usernsInitSyncAction, usernsSetIDsAction, initLoopbackAction, setHostAndDomainAction, makeFilesystemsPrivateAction, makeChrootSeparateFilesystemAction, statfsToMountFlags, bindMount, mountIntoChroot, mountIntoChrootAction, mountProcAction, mountDevshmAction, mountDevptsAction, pivotRootAction, lockMountsAction, getCloneSpawnPhases, runChildSetup, runChildSetupEntry, cloneChild, idMapToIdentityMap, unshareAndInitUserns): new procedures. * nix/local.mk (libutil_a_SOURCES): add spawn.cc. (libutil_headers): add spawn.hh. * nix/libstore/build.cc (restoreSIGPIPE, DerivationGoal::runChild, childEntry): removed procedures. (DerivationGoal::{dirsInChroot,env,readiness}): removed. (execBuilderOrBuiltin, execBuilderOrBuiltinAction, clearRootWritePermsAction): new procedures. (DerivationGoal::startBuilder): modified to use a CloneSpawnContext if chroot builds are available, otherwise a SpawnContext. Change-Id: Ifd50110de077378ee151502eda62b99973d083bf Change-Id: I76e10d3f928cc30566e1e6ca79077196972349f8 spawn.cc, util.cc, util.hh changes Change-Id: I287320e63197cb4f65665ee5b3fdb3a0e125ebac Signed-off-by: John Kehayias <john.kehayias@protonmail.com>
2025-06-24daemon: Implement ‘deletePath’ in terms of the *at functions.Reepca Russelstein1-17/+43
deletePath needs to be able to operate securely in unfriendly environments, where adversaries may be concurrently modifying the files being operated on. For example, directories that we are currently recursing through may be replaced with symbolic links. We err on the side of early failure here: if a file or directory is concurrently modified in a way that causes one of the system calls to fail, we throw an exception immediately instead of trying to adapt to the change. Note that we use fstat instead of fstatat for verifying the directory's st_mode field because AT_EMPTY_PATH is linux-specific. * nix/libutil/util.cc (_deletePathAt): new procedure. (_deletePath): use it. Change-Id: I7ccfe6f1f74dbab95617b24034494e0f63030582 Signed-off-by: Ludovic Courtès <ludo@gnu.org> Signed-off-by: John Kehayias <john.kehayias@protonmail.com>
2025-06-09daemon: Remove ‘foreach’ and ‘foreach_reverse’Congcong Kuo3-13/+6
‘foreach_reverse’ is not used anywhere * nix/libutil/util.hh (foreach, foreach_reverse): Remove. * nix/libstore/build.cc (addToWeakGoals): Use ‘std::none_of’ instead of macro ‘foreach’. (Goal::waiteeDone, Goal::amDone, UserLock::acquire, rewriteHashes, DerivationGoal::addWantedOutputs, DerivationGoal::haveDerivation, DerivationGoal::outputsSubstituted, DerivationGoal::repairClosure, DerivationGoal::inputsRealised, DerivationGoal::tryToBuild, DerivationGoal::buildDone, DerivationGoal::tryBuildHook, DerivationGoal::startBuilder, DerivationGoal::runChild, parseReferenceSpecifiers, DerivationGoal::registerOutputs, DerivationGoal::checkPathValidity, SubstitutionGoal::tryNext, SubstitutionGoal::referencesValid, Worker::removeGoal, Worker::childTerminated, Worker::run, Worker::waitForInput): Use range-based ‘for’ instead of macro ‘foreach’. * nix/libstore/derivations.cc (writeDerivation, unparseDerivation, hashDerivationModulo): Likewise. * nix/libstore/gc.cc (addAdditionalRoots, LocalStore::deletePathRecursive, LocalStore::canReachRoot, LocalStore::collectGarbage): Likewise. * nix/libstore/globals.cc (Settings::pack): Likewise. * nix/libstore/local-store.cc (checkDerivationOutputs, queryValidPaths, querySubstitutablePaths, querySubstitutablePathInfos, registerValidPaths, verifyStore, verifyPath): Likewise. * nix/libstore/misc.cc (computeFSClosure, dfsVisit, topoSortPaths): Likewise. * nix/libstore/optimise-store.cc (LocalStore::optimisePath_, LocalStore::optimiseStore): Likewise. * nix/libstore/pathlocks.cc (PathLocks::lockPaths, PathLocks::~PathLocks): Likewise. * nix/libstore/references.cc (search, scanForReferences): Likewise. * nix/libstore/store-api.cc (checkStoreName, computeStorePathForText, StoreAPI::makeValidityRegistration, showPaths, readStorePaths): Likewise. * nix/libutil/serialise.cc (writeStrings): Likewise. * nix/libutil/util.cc (concatStringsSep): Likewise. * nix/nix-daemon/nix-daemon.cc (performOp): Likewise. Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2025-06-03daemon: Remove ‘singleton’ and replace ‘typedef’ with ‘using’ in ↵Congcong Kuo2-16/+7
‘types.hh’ * nix/libutil/util.hh (singleton): Remove. * nix/libstore/build.cc (DerivationGoal::startBuilder) (SubstitutionGoal::tryNext, SubstitutionGoal::tryToRun) (LocalStore::ensurePath, LocalStore::repairPath): Use normal construction function instead of ‘singleton’. * nix/libstore/local-store.cc (LocalStore::addToStoreFromDump) (LocalStore::addTextToStore, LocalStore::importPath): Likewise. * nix/nix-daemon/nix-daemon.cc (performOp): Likewise. Change-Id: If0d929407c09482f3b506a1c51dfda70e29696dd Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2025-05-28daemon: Remove ‘AutoDeleteArray’.Congcong Kuo3-26/+12
* libutil/util.hh (AutoDeleteArray): Remove. * libutil/util.cc (readString, readStrings): Use ‘std::vector’ instead of ‘AutoDeleteArray’. * libutil/serialise.cc (readFile): Likewise. Change-Id: I45362998dbb8226874f66b77cd19f071f7bb2ab3 Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2025-03-26daemon: Close the read end of the logging pipe.Ludovic Courtès1-0/+3
* nix/libutil/util.cc (commonChildInit): Close ‘logPipe.readSide’. Reported-by: Reepca Russelstein <reepca@russelstein.xyz> Change-Id: Ia9e48d1afb85d7af52770e016f2b6832792044dd
2025-03-26daemon: Use ‘close_range’ where available.Ludovic Courtès1-6/+17
* nix/libutil/util.cc (closeMostFDs) [HAVE_CLOSE_RANGE]: Use ‘close_range’ when ‘exceptions’ is empty. * config-daemon.ac: Check for <linux/close_range.h> and the ‘close_range’ symbol. Change-Id: I12fa3bde58b003fcce5ea5a1fee1dcf9a92c0359
2024-05-13daemon: Loop over ‘copy_file_range’ upon short writes.Ludovic Courtès1-3/+8
Fixes <https://issues.guix.gnu.org/70877>. * nix/libutil/util.cc (copyFile): Loop over ‘copy_file_range’ instead of throwing upon short write. Reported-by: Ricardo Wurmus <rekado@elephly.net> Change-Id: Id7b8a65ea59006c2d91bc23732309a68665b9ca0
2024-03-12daemon: Address shortcoming in previous security fix for CVE-2024-27297.Ludovic Courtès2-3/+8
This is a followup to 8f4ffb3fae133bb21d7991e97c2f19a7108b1143. Commit 8f4ffb3fae133bb21d7991e97c2f19a7108b1143 fell short in two ways: (1) it didn’t have any effet for fixed-output derivations performed in a chroot, which is the case for all of them except those using “builtin:download” and “builtin:git-download”, and (2) it did not preserve ownership when copying, leading to “suspicious ownership or permission […] rejecting this build output” errors. * nix/libstore/build.cc (DerivationGoal::buildDone): Account for ‘chrootRootDir’ when copying ‘drv.outputs’. * nix/libutil/util.cc (copyFileRecursively): Add ‘fchown’ and ‘fchownat’ calls to preserve file ownership; this is necessary for chrooted fixed-output derivation builds. * nix/libutil/util.hh: Update comment. Change-Id: Ib59f040e98fed59d1af81d724b874b592cbef156
2024-03-11daemon: Protect against FD escape when building fixed-output derivations ↵Ludovic Courtès2-5/+113
(CVE-2024-27297). This fixes a security issue (CVE-2024-27297) whereby a fixed-output derivation build process could open a writable file descriptor to its output, send it to some outside process for instance over an abstract AF_UNIX socket, which would then allow said process to modify the file in the store after it has been marked as “valid”. Vulnerability discovered by puck <https://github.com/puckipedia>. Nix security advisory: https://github.com/NixOS/nix/security/advisories/GHSA-2ffj-w4mj-pg37 Nix fix: https://github.com/NixOS/nix/commit/244f3eee0bbc7f11e9b383a15ed7368e2c4becc9 * nix/libutil/util.cc (readDirectory): Add variants that take a DIR* and a file descriptor. Rewrite the ‘Path’ variant accordingly. (copyFile, copyFileRecursively): New functions. * nix/libutil/util.hh (copyFileRecursively): New declaration. * nix/libstore/build.cc (DerivationGoal::buildDone): When ‘fixedOutput’ is true, call ‘copyFileRecursively’ followed by ‘rename’ on each output. Change-Id: I7952d41093eed26e123e38c14a4c1424be1ce1c4 Reported-by: Picnoir <picnoir@alternativebit.fr>, Théophane Hufschmitt <theophane.hufschmitt@tweag.io> Change-Id: Idb5f2757f35af86b032a9851cecb19b70227bd88
2023-01-09daemon: Improve error message for wrong hash sizes.Ludovic Courtès1-2/+5
* nix/libutil/hash.cc (parseHash): Show the hash algorithm name and expected size in the error message. * tests/derivations.scm ("fixed-output derivation, invalid hash size"): New test.
2022-12-18daemon: Make "opening file" error messages distinguishable.Ludovic Courtès2-3/+3
* nix/libstore/build.cc (DerivationGoal::openLogFile): Customize "opening file" error message. * nix/libutil/hash.cc (hashFile): Likewise. * nix/libutil/util.cc (readFile, writeFile): Likewise.
2021-11-19daemon: Micro-optimize 'deletePath'.Ludovic Courtès1-3/+6
'remove' calls 'unlink' first and falls back to 'rmdir' upon EISDIR. This change gets rid of the 'unlink' call for every directory being removed. * nix/libutil/util.cc (_deletePath): Call 'unlink' or 'rmdir' depending on 'st.st_mode', rather than call 'remove'.
2020-12-08daemon: 'Agent' constructor takes a list of environment variables.Ludovic Courtès2-3/+10
* nix/libutil/util.hh (struct Agent)[Agent]: Add 'env' parameter. * nix/libutil/util.cc (Agent::Agent): Honor it.
2020-09-14daemon: Move 'Agent' to libutil.Ludovic Courtès2-0/+109
* nix/libstore/build.cc (DerivationGoal::tryBuildHook): Add "offload" to 'args' and pass settings.guixProgram as the first argument to Agent::Agent. (pathNullDevice, commonChildInit, Agent, Agent::Agent) (Agent::~Agent): Move to... * nix/libutil/util.cc: ... here. * nix/libutil/util.hh (struct Agent, commonChildInit): New declarations.
2020-06-27daemon: Recognize SHA3 and BLAKE2s.Ludovic Courtès2-1/+10
* nix/libutil/hash.hh (HashType): Add htSHA3_256, htSHA3_512, and htBLAKE2s_256. * nix/libutil/hash.cc (parseHashType, printHashType): Recognize them. * tests/store.scm ("add-to-store"): Test these algorithms.
2020-06-27daemon: Remove OpenSSL hash compatibility wrappers.Ludovic Courtès7-270/+24
* nix/libutil/hash.cc (struct Ctx): Copy from gcrypt-hash.hh. (start, update, finish): Use gcrypt functions directly instead of OpenSSL-like wrappers. * nix/libutil/gcrypt-hash.cc, nix/libutil/gcrypt-hash.hh, nix/libutil/md5.h, nix/libutil/sha1.h, nix/libutil/sha256.h, nix/libutil/sha512.h: Remove. * nix/local.mk (libutil_a_SOURCES, libutil_headers): Adjust accordingly.
2020-06-27daemon: Map directly to gcrypt hash functions.Ludovic Courtès2-13/+12
* nix/libutil/hash.hh (HashType): Map directly to GCRY_MD_ values. (md5HashSize, sha1HashSize, sha256HashSize, sha512HashSize): Remove. * nix/libutil/hash.cc (Hash::Hash): Use 'gcry_md_get_algo_dlen'.
2020-06-24nix: Tweak .gitignore files.Christopher Baines1-2/+0
Remove .gitignore entries where they match source files that are tracked in Git. This is relevant to me at least, as some code searching tools use .gitignore files and will ignore matched files.
2020-03-26daemon: Avoid kill -1 bug on the Hurd.Manolis Ragkousis1-0/+8
This allows for native builds on the Hurd, doing sudo ./pre-inst-env guix-daemon --disable-chroot --build-users-group=guixbuild & ./pre-inst-env guix build hello * nix/libutil/util.cc (killUser)[__GNU__]: Avoid kill -1 bug; kill only current process and ignore SIGKILL status in parent. Co-authored-by: Jan Nieuwenhuizen <janneke@gnu.org>
2020-01-12daemon: Account for deleted store files when deduplication is on.Ludovic Courtès2-7/+9
Previously, a store item that is a regular file would not be accounted for in the 'bytesFreed' value computed by 'deletePath' because its 'st_nlink' count would always be >= 2. This commit fixes that. * nix/libutil/util.hh (deletePath): Add optional 'linkThreshold' argument. * nix/libutil/util.cc (_deletePath): Add 'linkThreshold' argument and honor it. Pass it down in recursive call. (deletePath): Add 'linkThreshold' and honor it. * nix/libstore/gc.cc (LocalStore::deleteGarbage): Pass 'linkThreshold' argument to 'deletePath', with a value of 2 when PATH is a store item and deduplication is on.
2019-11-29daemon: 'pathExists' uses 'statx' when available.Ludovic Courtès1-0/+5
* nix/libutil/util.cc (pathExists) [HAVE_STATX]: New code.
2019-11-27daemon: 'deletePath' uses 'statx' when available.Ludovic Courtès1-0/+14
* nix/libutil/util.cc (_deletePath) [HAVE_STATX]: Use 'statx'.
2019-08-30daemon: Don't reply on 'st_blocks'.Eelco Dolstra1-1/+1
Ported by Ludovic Courtès <ludo@gnu.org> from <https://github.com/NixOS/nix/commit/a2c4fcd5e9782dc8d2998773380c7171ee53b813>. * nix/libstore/gc.cc (LocalStore::removeUnusedLinks): Use 'st.st_size' instead of 'st.st_blocks * 512'. * nix/libutil/util.cc (_deletePath): Likewise.
2018-12-16daemon: Use unbranded phrases in comments and messages.Ludovic Courtès1-1/+1
* nix/libstore/build.cc, nix/libstore/globals.cc, nix/libstore/gc.cc, nix/libstore/local-store.cc, nix/libstore/optimise-store.cc, nix/libstore/store-api.cc, nix/libutil/archive.cc, nix/nix-daemon/nix-daemon.cc: Replace "Nix store" by "store", and "Nix daemon" by "build daemon".
2018-10-02daemon: Remove "case hack" for nars.Ludovic Courtès2-35/+1
This code has never been of any use in Guix. * nix/libutil/archive.cc (useCaseHack): Remove. (parse): Keep only the alternate branch in "if (useCaseHack)".
2017-08-18nix: Remove unused function.Andy Wingo2-21/+0
* nix/libutil/util.hh: * nix/libutil/util.cc (decodeOctalEscaped): Remove unused and buggy function.
2016-05-31daemon: Remove unused XML output code.Ludovic Courtès2-163/+0
* nix/local.mk (libutil_a_SOURCES): Remove libutil/xml-writer.cc. (libutil_headers): Remove libutil/xml-writer.hh. * nix/libutil/xml-writer.hh, nix/libutil/xml-writer.cc: Remove.
2015-12-02daemon: Fix namespace issue.Eelco Dolstra1-2/+2
2015-12-02daemon: Support SHA-512 hashes.Eelco Dolstra3-2/+46
Fixes #679. Note: on x86_64, SHA-512 is considerably faster than SHA-256 (198 MB/s versus 131 MB/s). Co-authored-by: Ludovic Courtès <ludo@gnu.org>