2021-02-23 08:26:35 +02:00
|
|
|
#pragma once
|
2023-04-01 06:18:41 +03:00
|
|
|
///@file
|
2021-02-23 08:26:35 +02:00
|
|
|
|
2021-02-26 17:20:33 +02:00
|
|
|
#include "derivation-goal.hh"
|
2021-02-23 08:26:35 +02:00
|
|
|
#include "local-store.hh"
|
|
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
2021-02-26 17:20:33 +02:00
|
|
|
struct LocalDerivationGoal : public DerivationGoal
|
2021-02-23 08:26:35 +02:00
|
|
|
{
|
2021-02-26 17:20:33 +02:00
|
|
|
LocalStore & getLocalStore();
|
|
|
|
|
2021-02-23 08:26:35 +02:00
|
|
|
/* User selected for running the builder. */
|
|
|
|
std::unique_ptr<UserLock> buildUser;
|
|
|
|
|
|
|
|
/* The process ID of the builder. */
|
|
|
|
Pid pid;
|
|
|
|
|
2022-11-18 11:39:28 +02:00
|
|
|
/* The cgroup of the builder, if any. */
|
|
|
|
std::optional<Path> cgroup;
|
|
|
|
|
2021-02-23 08:26:35 +02:00
|
|
|
/* The temporary directory. */
|
|
|
|
Path tmpDir;
|
|
|
|
|
|
|
|
/* The path of the temporary directory in the sandbox. */
|
|
|
|
Path tmpDirInSandbox;
|
|
|
|
|
2023-03-15 11:37:39 +02:00
|
|
|
/* Master side of the pseudoterminal used for the builder's
|
|
|
|
standard output/error. */
|
|
|
|
AutoCloseFD builderOut;
|
2021-02-23 08:26:35 +02:00
|
|
|
|
|
|
|
/* Pipe for synchronising updates to the builder namespaces. */
|
|
|
|
Pipe userNamespaceSync;
|
|
|
|
|
2021-10-09 01:55:08 +03:00
|
|
|
/* The mount namespace and user namespace of the builder, used to add additional
|
2021-02-23 08:26:35 +02:00
|
|
|
paths to the sandbox as a result of recursive Nix calls. */
|
|
|
|
AutoCloseFD sandboxMountNamespace;
|
2021-10-09 01:55:08 +03:00
|
|
|
AutoCloseFD sandboxUserNamespace;
|
2021-02-23 08:26:35 +02:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
Path chrootRootDir;
|
|
|
|
|
|
|
|
/* RAII object to delete the chroot directory. */
|
|
|
|
std::shared_ptr<AutoDelete> autoDelChroot;
|
|
|
|
|
|
|
|
/* Whether to run the build in a private network namespace. */
|
|
|
|
bool privateNetwork = false;
|
|
|
|
|
|
|
|
/* 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<Path, ChrootPath> DirsInChroot; // maps target path to source path
|
|
|
|
DirsInChroot dirsInChroot;
|
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
typedef map<std::string, std::string> Environment;
|
2021-02-23 08:26:35 +02:00
|
|
|
Environment env;
|
|
|
|
|
|
|
|
#if __APPLE__
|
2022-02-28 16:21:03 +02:00
|
|
|
typedef std::string SandboxProfile;
|
2021-02-23 08:26:35 +02:00
|
|
|
SandboxProfile additionalSandboxProfile;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Hash rewriting. */
|
|
|
|
StringMap inputRewrites, outputRewrites;
|
|
|
|
typedef map<StorePath, StorePath> RedirectedOutputs;
|
|
|
|
RedirectedOutputs redirectedOutputs;
|
|
|
|
|
|
|
|
/* The outputs 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-addressed 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;
|
|
|
|
|
|
|
|
/* Path registration info from the previous round, if we're
|
|
|
|
building multiple times. Since this contains the hash, it
|
|
|
|
allows us to compare whether two rounds produced the same
|
|
|
|
result. */
|
|
|
|
std::map<Path, ValidPathInfo> prevInfos;
|
|
|
|
|
2022-11-17 12:56:45 +02:00
|
|
|
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(); }
|
2021-02-23 08:26:35 +02:00
|
|
|
|
|
|
|
const static Path homeDir;
|
|
|
|
|
|
|
|
/* The recursive Nix daemon socket. */
|
|
|
|
AutoCloseFD daemonSocket;
|
|
|
|
|
|
|
|
/* The daemon main thread. */
|
|
|
|
std::thread daemonThread;
|
|
|
|
|
|
|
|
/* The daemon worker threads. */
|
|
|
|
std::vector<std::thread> daemonWorkerThreads;
|
|
|
|
|
|
|
|
/* Paths that were added via recursive Nix calls. */
|
|
|
|
StorePathSet addedPaths;
|
|
|
|
|
2021-06-23 18:27:18 +03:00
|
|
|
/* Realisations that were added via recursive Nix calls. */
|
|
|
|
std::set<DrvOutput> addedDrvOutputs;
|
|
|
|
|
2021-02-23 08:26:35 +02:00
|
|
|
/* 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/<bla>' where
|
|
|
|
/nix/store/<bla> is some arbitrary path in a binary cache). */
|
|
|
|
bool isAllowed(const StorePath & path)
|
|
|
|
{
|
|
|
|
return inputPaths.count(path) || addedPaths.count(path);
|
|
|
|
}
|
2021-06-23 18:27:18 +03:00
|
|
|
bool isAllowed(const DrvOutput & id)
|
|
|
|
{
|
|
|
|
return addedDrvOutputs.count(id);
|
|
|
|
}
|
|
|
|
|
2021-04-05 16:48:18 +03:00
|
|
|
bool isAllowed(const DerivedPath & req);
|
2021-02-23 08:26:35 +02:00
|
|
|
|
|
|
|
friend struct RestrictedStore;
|
|
|
|
|
2021-02-26 17:20:33 +02:00
|
|
|
using DerivationGoal::DerivationGoal;
|
|
|
|
|
|
|
|
virtual ~LocalDerivationGoal() override;
|
2021-02-23 08:26:35 +02:00
|
|
|
|
|
|
|
/* Whether we need to perform hash rewriting if there are valid output paths. */
|
|
|
|
bool needsHashRewrite();
|
|
|
|
|
2021-02-26 17:31:15 +02:00
|
|
|
/* The additional states. */
|
2021-02-26 17:20:33 +02:00
|
|
|
void tryLocalBuild() override;
|
2021-02-23 08:26:35 +02:00
|
|
|
|
|
|
|
/* Start building a derivation. */
|
|
|
|
void startBuilder();
|
|
|
|
|
|
|
|
/* Fill in the environment for the builder. */
|
|
|
|
void initEnv();
|
|
|
|
|
|
|
|
/* Setup tmp dir location. */
|
|
|
|
void initTmpDir();
|
|
|
|
|
|
|
|
/* Write a JSON file containing the derivation attributes. */
|
|
|
|
void writeStructuredAttrs();
|
|
|
|
|
|
|
|
void 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);
|
|
|
|
|
2021-02-26 17:20:33 +02:00
|
|
|
int getChildStatus() override;
|
|
|
|
|
2021-02-23 08:26:35 +02:00
|
|
|
/* Run the builder's process. */
|
2023-03-20 18:04:57 +02:00
|
|
|
void runChild();
|
2021-02-23 08:26:35 +02:00
|
|
|
|
|
|
|
/* Check that the derivation outputs all exist and register them
|
|
|
|
as valid. */
|
2022-03-08 20:50:46 +02:00
|
|
|
DrvOutputs registerOutputs() override;
|
2021-02-23 08:26:35 +02:00
|
|
|
|
2021-03-08 18:32:20 +02:00
|
|
|
void signRealisation(Realisation &) override;
|
|
|
|
|
2021-02-23 08:26:35 +02:00
|
|
|
/* 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<std::string, ValidPathInfo> & outputs);
|
|
|
|
|
2021-02-26 17:20:33 +02:00
|
|
|
/* Close the read side of the logger pipe. */
|
|
|
|
void closeReadPipes() override;
|
|
|
|
|
|
|
|
/* Cleanup hooks for buildDone() */
|
|
|
|
void cleanupHookFinally() override;
|
|
|
|
void cleanupPreChildKill() override;
|
|
|
|
void cleanupPostChildKill() override;
|
|
|
|
bool cleanupDecideWhetherDiskFull() override;
|
|
|
|
void cleanupPostOutputsRegisteredModeCheck() override;
|
|
|
|
void cleanupPostOutputsRegisteredModeNonCheck() override;
|
|
|
|
|
|
|
|
bool isReadDesc(int fd) override;
|
|
|
|
|
2021-02-23 08:26:35 +02:00
|
|
|
/* Delete the temporary directory, if we have one. */
|
|
|
|
void deleteTmpDir(bool force);
|
|
|
|
|
|
|
|
/* Forcibly kill the child process, if any. */
|
2021-02-26 17:20:33 +02:00
|
|
|
void killChild() override;
|
2021-02-23 08:26:35 +02:00
|
|
|
|
2022-11-18 11:39:28 +02:00
|
|
|
/* Kill any processes running under the build user UID or in the
|
|
|
|
cgroup of the build. */
|
2022-11-18 14:40:59 +02:00
|
|
|
void killSandbox(bool getStats);
|
2022-11-18 11:39:28 +02:00
|
|
|
|
2021-02-23 08:26:35 +02:00
|
|
|
/* 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. */
|
|
|
|
/* FIXME add option to randomize, so we can audit whether our
|
|
|
|
rewrites caught everything */
|
|
|
|
StorePath makeFallbackPath(std::string_view outputName);
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|