diff --git a/src/libstore/build/worker.cc b/src/libstore/build/worker.cc index dad460a1e..bab3bd470 100644 --- a/src/libstore/build/worker.cc +++ b/src/libstore/build/worker.cc @@ -68,7 +68,7 @@ std::shared_ptr Worker::makeDerivationGoal(const StorePath & drv return #ifndef _WIN32 // TODO Enable building on Windows dynamic_cast(&store) - ? std::make_shared(drvPath, wantedOutputs, *this, buildMode) + ? makeLocalDerivationGoal(drvPath, wantedOutputs, *this, buildMode) : #endif std::make_shared(drvPath, wantedOutputs, *this, buildMode); @@ -82,7 +82,7 @@ std::shared_ptr Worker::makeBasicDerivationGoal(const StorePath return #ifndef _WIN32 // TODO Enable building on Windows dynamic_cast(&store) - ? std::make_shared(drvPath, drv, wantedOutputs, *this, buildMode) + ? makeLocalDerivationGoal(drvPath, drv, wantedOutputs, *this, buildMode) : #endif std::make_shared(drvPath, drv, wantedOutputs, *this, buildMode); diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index c73c61371..d0ee0bdc1 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -1582,20 +1582,6 @@ void LocalStore::addSignatures(const StorePath & storePath, const StringSet & si } -void LocalStore::signPathInfo(ValidPathInfo & info) -{ - // FIXME: keep secret keys in memory. - - auto secretKeyFiles = settings.secretKeyFiles; - - for (auto & secretKeyFile : secretKeyFiles.get()) { - SecretKey secretKey(readFile(secretKeyFile)); - LocalSigner signer(std::move(secretKey)); - info.sign(*this, signer); - } -} - - std::optional> LocalStore::queryRealisationCore_( LocalStore::State & state, const DrvOutput & id) diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 07d9cec0a..680318d43 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -396,12 +396,6 @@ private: bool isValidPath_(State & state, const StorePath & path); void queryReferrers(State & state, const StorePath & path, StorePathSet & referrers); - /** - * Add signatures to a ValidPathInfo or Realisation using the secret keys - * specified by the ‘secret-key-files’ option. - */ - void signPathInfo(ValidPathInfo & info); - void addBuildLog(const StorePath & drvPath, std::string_view log) override; friend struct LocalDerivationGoal; diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index e99e96aac..172c82324 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -1274,6 +1274,21 @@ Derivation Store::readDerivation(const StorePath & drvPath) Derivation Store::readInvalidDerivation(const StorePath & drvPath) { return readDerivationCommon(*this, drvPath, false); } + +void Store::signPathInfo(ValidPathInfo & info) +{ + // FIXME: keep secret keys in memory. + + auto secretKeyFiles = settings.secretKeyFiles; + + for (auto & secretKeyFile : secretKeyFiles.get()) { + SecretKey secretKey(readFile(secretKeyFile)); + LocalSigner signer(std::move(secretKey)); + info.sign(*this, signer); + } +} + + void Store::signRealisation(Realisation & realisation) { // FIXME: keep secret keys in memory. diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 83ca8344b..1ae4ac064 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -622,6 +622,12 @@ public: virtual void addSignatures(const StorePath & storePath, const StringSet & sigs) { unsupported("addSignatures"); } + /** + * Add signatures to a ValidPathInfo or Realisation using the secret keys + * specified by the ‘secret-key-files’ option. + */ + void signPathInfo(ValidPathInfo & info); + void signRealisation(Realisation &); /* Utility functions. */ diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc index 7f6bace86..fac83b0c1 100644 --- a/src/libstore/unix/build/local-derivation-goal.cc +++ b/src/libstore/unix/build/local-derivation-goal.cc @@ -1,4 +1,6 @@ #include "local-derivation-goal.hh" +#include "local-store.hh" +#include "processes.hh" #include "indirect-root-store.hh" #include "hook-instance.hh" #include "worker.hh" @@ -73,6 +75,302 @@ extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, namespace nix { +struct LocalDerivationGoal : public DerivationGoal +{ + LocalStore & getLocalStore(); + + /** + * User selected for running the builder. + */ + std::unique_ptr buildUser; + + /** + * The process ID of the builder. + */ + Pid pid; + + /** + * The cgroup of the builder, if any. + */ + std::optional cgroup; + + /** + * The temporary directory used for the build. + */ + Path tmpDir; + + /** + * The top-level temporary directory. `tmpDir` is either equal to + * or a child of this directory. + */ + Path topTmpDir; + + /** + * The path of the temporary directory in the sandbox. + */ + Path tmpDirInSandbox; + + /** + * Master side of the pseudoterminal used for the builder's + * standard output/error. + */ + AutoCloseFD builderOut; + + /** + * Pipe for synchronising updates to the builder namespaces. + */ + Pipe userNamespaceSync; + + /** + * The mount namespace and user namespace of the builder, used to add additional + * paths to the sandbox as a result of recursive Nix calls. + */ + AutoCloseFD sandboxMountNamespace; + AutoCloseFD sandboxUserNamespace; + + /** + * On Linux, whether we're doing the build in its own user + * namespace. + */ + bool usingUserNamespace = true; + + /** + * Whether we're currently doing a chroot build. + */ + bool useChroot = false; + + /** + * The root of the chroot environment. + */ + Path chrootRootDir; + + /** + * RAII object to delete the chroot directory. + */ + std::shared_ptr autoDelChroot; + + /** + * Stuff we need to pass to initChild(). + */ + struct ChrootPath { + Path source; + bool optional; + ChrootPath(Path source = "", bool optional = false) + : source(source), optional(optional) + { } + }; + typedef map PathsInChroot; // maps target path to source path + PathsInChroot pathsInChroot; + + typedef map Environment; + Environment env; + + /** + * Hash rewriting. + */ + StringMap inputRewrites, outputRewrites; + typedef map RedirectedOutputs; + RedirectedOutputs redirectedOutputs; + + /** + * The output paths used during the build. + * + * - Input-addressed derivations or fixed content-addressed outputs are + * sometimes built when some of their outputs already exist, and can not + * be hidden via sandboxing. We use temporary locations instead and + * rewrite after the build. Otherwise the regular predetermined paths are + * put here. + * + * - Floating content-addressing derivations do not know their final build + * output paths until the outputs are hashed, so random locations are + * used, and then renamed. The randomness helps guard against hidden + * self-references. + */ + OutputPathMap scratchOutputs; + + uid_t sandboxUid() { return usingUserNamespace ? (!buildUser || buildUser->getUIDCount() == 1 ? 1000 : 0) : buildUser->getUID(); } + gid_t sandboxGid() { return usingUserNamespace ? (!buildUser || buildUser->getUIDCount() == 1 ? 100 : 0) : buildUser->getGID(); } + + const static Path homeDir; + + /** + * The recursive Nix daemon socket. + */ + AutoCloseFD daemonSocket; + + /** + * The daemon main thread. + */ + std::thread daemonThread; + + /** + * The daemon worker threads. + */ + std::vector daemonWorkerThreads; + + /** + * Paths that were added via recursive Nix calls. + */ + StorePathSet addedPaths; + + /** + * Realisations that were added via recursive Nix calls. + */ + std::set addedDrvOutputs; + + /** + * Recursive Nix calls are only allowed to build or realize paths + * in the original input closure or added via a recursive Nix call + * (so e.g. you can't do 'nix-store -r /nix/store/' where + * /nix/store/ is some arbitrary path in a binary cache). + */ + bool isAllowed(const StorePath & path) + { + return inputPaths.count(path) || addedPaths.count(path); + } + bool isAllowed(const DrvOutput & id) + { + return addedDrvOutputs.count(id); + } + + bool isAllowed(const DerivedPath & req); + + friend struct RestrictedStore; + + using DerivationGoal::DerivationGoal; + + virtual ~LocalDerivationGoal() override; + + /** + * Whether we need to perform hash rewriting if there are valid output paths. + */ + bool needsHashRewrite(); + + /** + * The additional states. + */ + Goal::Co tryLocalBuild() override; + + /** + * Start building a derivation. + */ + void startBuilder(); + + /** + * Fill in the environment for the builder. + */ + void initEnv(); + + /** + * Process messages send by the sandbox initialization. + */ + void processSandboxSetupMessages(); + + /** + * Setup tmp dir location. + */ + void initTmpDir(); + + /** + * Write a JSON file containing the derivation attributes. + */ + void writeStructuredAttrs(); + + /** + * Start an in-process nix daemon thread for recursive-nix. + */ + void startDaemon(); + + /** + * Stop the in-process nix daemon thread. + * @see startDaemon + */ + void stopDaemon(); + + /** + * Add 'path' to the set of paths that may be referenced by the + * outputs, and make it appear in the sandbox. + */ + void addDependency(const StorePath & path); + + /** + * Make a file owned by the builder. + */ + void chownToBuilder(const Path & path); + + /** + * Run the builder's process. + */ + void runChild(); + + /** + * Check that the derivation outputs all exist and register them + * as valid. + */ + SingleDrvOutputs registerOutputs(); + + /** + * Check that an output meets the requirements specified by the + * 'outputChecks' attribute (or the legacy + * '{allowed,disallowed}{References,Requisites}' attributes). + */ + void checkOutputs(const std::map & outputs); + + bool isReadDesc(int fd) override; + + /** + * Delete the temporary directory, if we have one. + */ + void deleteTmpDir(bool force); + + /** + * Forcibly kill the child process, if any. + * + * Called by destructor, can't be overridden + */ + void killChild() override final; + + /** + * Kill any processes running under the build user UID or in the + * cgroup of the build. + */ + void killSandbox(bool getStats); + + bool cleanupDecideWhetherDiskFull(); + + /** + * Create alternative path calculated from but distinct from the + * input, so we can avoid overwriting outputs (or other store paths) + * that already exist. + */ + StorePath makeFallbackPath(const StorePath & path); + + /** + * Make a path to another based on the output name along with the + * derivation hash. + * + * @todo Add option to randomize, so we can audit whether our + * rewrites caught everything + */ + StorePath makeFallbackPath(OutputNameView outputName); +}; + +std::shared_ptr makeLocalDerivationGoal( + const StorePath & drvPath, + const OutputsSpec & wantedOutputs, Worker & worker, + BuildMode buildMode) +{ + return std::make_shared(drvPath, wantedOutputs, worker, buildMode); +} + +std::shared_ptr makeLocalDerivationGoal( + const StorePath & drvPath, const BasicDerivation & drv, + const OutputsSpec & wantedOutputs, Worker & worker, + BuildMode buildMode) +{ + return std::make_shared(drvPath, drv, wantedOutputs, worker, buildMode); +} + void handleDiffHook( uid_t uid, uid_t gid, const Path & tryA, const Path & tryB, diff --git a/src/libstore/unix/build/local-derivation-goal.hh b/src/libstore/unix/build/local-derivation-goal.hh index ec8cf2c0b..7659e8f99 100644 --- a/src/libstore/unix/build/local-derivation-goal.hh +++ b/src/libstore/unix/build/local-derivation-goal.hh @@ -2,289 +2,25 @@ ///@file #include "derivation-goal.hh" -#include "local-store.hh" -#include "processes.hh" namespace nix { -struct LocalDerivationGoal : public DerivationGoal -{ - LocalStore & getLocalStore(); +/** + * Create a local derivation goal, see `DerivationGoal` for info on each + * constructor variant. + */ +std::shared_ptr makeLocalDerivationGoal( + const StorePath & drvPath, + const OutputsSpec & wantedOutputs, Worker & worker, + BuildMode buildMode = bmNormal); - /** - * User selected for running the builder. - */ - std::unique_ptr buildUser; - - /** - * The process ID of the builder. - */ - Pid pid; - - /** - * The cgroup of the builder, if any. - */ - std::optional cgroup; - - /** - * The temporary directory used for the build. - */ - Path tmpDir; - - /** - * The top-level temporary directory. `tmpDir` is either equal to - * or a child of this directory. - */ - Path topTmpDir; - - /** - * The path of the temporary directory in the sandbox. - */ - Path tmpDirInSandbox; - - /** - * Master side of the pseudoterminal used for the builder's - * standard output/error. - */ - AutoCloseFD builderOut; - - /** - * Pipe for synchronising updates to the builder namespaces. - */ - Pipe userNamespaceSync; - - /** - * The mount namespace and user namespace of the builder, used to add additional - * paths to the sandbox as a result of recursive Nix calls. - */ - AutoCloseFD sandboxMountNamespace; - AutoCloseFD sandboxUserNamespace; - - /** - * On Linux, whether we're doing the build in its own user - * namespace. - */ - bool usingUserNamespace = true; - - /** - * Whether we're currently doing a chroot build. - */ - bool useChroot = false; - - /** - * The root of the chroot environment. - */ - Path chrootRootDir; - - /** - * RAII object to delete the chroot directory. - */ - std::shared_ptr autoDelChroot; - - /** - * Stuff we need to pass to initChild(). - */ - struct ChrootPath { - Path source; - bool optional; - ChrootPath(Path source = "", bool optional = false) - : source(source), optional(optional) - { } - }; - typedef map PathsInChroot; // maps target path to source path - PathsInChroot pathsInChroot; - - typedef map Environment; - Environment env; - - /** - * Hash rewriting. - */ - StringMap inputRewrites, outputRewrites; - typedef map RedirectedOutputs; - RedirectedOutputs redirectedOutputs; - - /** - * The output paths used during the build. - * - * - Input-addressed derivations or fixed content-addressed outputs are - * sometimes built when some of their outputs already exist, and can not - * be hidden via sandboxing. We use temporary locations instead and - * rewrite after the build. Otherwise the regular predetermined paths are - * put here. - * - * - Floating content-addressing derivations do not know their final build - * output paths until the outputs are hashed, so random locations are - * used, and then renamed. The randomness helps guard against hidden - * self-references. - */ - OutputPathMap scratchOutputs; - - uid_t sandboxUid() { return usingUserNamespace ? (!buildUser || buildUser->getUIDCount() == 1 ? 1000 : 0) : buildUser->getUID(); } - gid_t sandboxGid() { return usingUserNamespace ? (!buildUser || buildUser->getUIDCount() == 1 ? 100 : 0) : buildUser->getGID(); } - - const static Path homeDir; - - /** - * The recursive Nix daemon socket. - */ - AutoCloseFD daemonSocket; - - /** - * The daemon main thread. - */ - std::thread daemonThread; - - /** - * The daemon worker threads. - */ - std::vector daemonWorkerThreads; - - /** - * Paths that were added via recursive Nix calls. - */ - StorePathSet addedPaths; - - /** - * Realisations that were added via recursive Nix calls. - */ - std::set addedDrvOutputs; - - /** - * Recursive Nix calls are only allowed to build or realize paths - * in the original input closure or added via a recursive Nix call - * (so e.g. you can't do 'nix-store -r /nix/store/' where - * /nix/store/ is some arbitrary path in a binary cache). - */ - bool isAllowed(const StorePath & path) - { - return inputPaths.count(path) || addedPaths.count(path); - } - bool isAllowed(const DrvOutput & id) - { - return addedDrvOutputs.count(id); - } - - bool isAllowed(const DerivedPath & req); - - friend struct RestrictedStore; - - using DerivationGoal::DerivationGoal; - - virtual ~LocalDerivationGoal() override; - - /** - * Whether we need to perform hash rewriting if there are valid output paths. - */ - bool needsHashRewrite(); - - /** - * The additional states. - */ - Goal::Co tryLocalBuild() override; - - /** - * Start building a derivation. - */ - void startBuilder(); - - /** - * Fill in the environment for the builder. - */ - void initEnv(); - - /** - * Process messages send by the sandbox initialization. - */ - void processSandboxSetupMessages(); - - /** - * Setup tmp dir location. - */ - void initTmpDir(); - - /** - * Write a JSON file containing the derivation attributes. - */ - void writeStructuredAttrs(); - - /** - * Start an in-process nix daemon thread for recursive-nix. - */ - void startDaemon(); - - /** - * Stop the in-process nix daemon thread. - * @see startDaemon - */ - void stopDaemon(); - - /** - * Add 'path' to the set of paths that may be referenced by the - * outputs, and make it appear in the sandbox. - */ - void addDependency(const StorePath & path); - - /** - * Make a file owned by the builder. - */ - void chownToBuilder(const Path & path); - - /** - * Run the builder's process. - */ - void runChild(); - - /** - * Check that the derivation outputs all exist and register them - * as valid. - */ - SingleDrvOutputs registerOutputs(); - - /** - * Check that an output meets the requirements specified by the - * 'outputChecks' attribute (or the legacy - * '{allowed,disallowed}{References,Requisites}' attributes). - */ - void checkOutputs(const std::map & outputs); - - bool isReadDesc(int fd) override; - - /** - * Delete the temporary directory, if we have one. - */ - void deleteTmpDir(bool force); - - /** - * Forcibly kill the child process, if any. - * - * Called by destructor, can't be overridden - */ - void killChild() override final; - - /** - * Kill any processes running under the build user UID or in the - * cgroup of the build. - */ - void killSandbox(bool getStats); - - bool cleanupDecideWhetherDiskFull(); - - /** - * Create alternative path calculated from but distinct from the - * input, so we can avoid overwriting outputs (or other store paths) - * that already exist. - */ - StorePath makeFallbackPath(const StorePath & path); - - /** - * Make a path to another based on the output name along with the - * derivation hash. - * - * @todo Add option to randomize, so we can audit whether our - * rewrites caught everything - */ - StorePath makeFallbackPath(OutputNameView outputName); -}; +/** + * Create a local derivation goal, see `DerivationGoal` for info on each + * constructor variant. + */ +std::shared_ptr makeLocalDerivationGoal( + const StorePath & drvPath, const BasicDerivation & drv, + const OutputsSpec & wantedOutputs, Worker & worker, + BuildMode buildMode = bmNormal); }