1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-17 07:52:43 +01:00

Make building only require a LocalFSStore

This is the crucial first step to allowing client-side building --- i.e.
building locally but using some form of RPC to manipulate metadata
rather than interact with a concrete form of persisting metadata like
the SQLite database.

To facilitate this, a few methods were hastily moved from `LocalStore`
to `LocalFSStore`. We should not just accept that as good enough to
merge, but carefully consider the trust/security implications of this,
and the proper division of labor between the less-trusted "builder" and
the more-trusted "store".
This commit is contained in:
John Ericson 2023-11-19 10:28:52 -05:00
parent 82e23c117e
commit 29be7958e4
6 changed files with 58 additions and 30 deletions

View file

@ -668,7 +668,7 @@ void DerivationGoal::tryToBuild()
PathSet lockFiles; PathSet lockFiles;
/* FIXME: Should lock something like the drv itself so we don't build same /* FIXME: Should lock something like the drv itself so we don't build same
CA drv concurrently */ CA drv concurrently */
if (dynamic_cast<LocalStore *>(&worker.store)) { if (dynamic_cast<LocalFSStore *>(&worker.store)) {
/* If we aren't a local store, we might need to use the local store as /* If we aren't a local store, we might need to use the local store as
a build remote, but that would cause a deadlock. */ a build remote, but that would cause a deadlock. */
/* FIXME: Make it so we can use ourselves as a build remote even if we /* FIXME: Make it so we can use ourselves as a build remote even if we
@ -1240,7 +1240,7 @@ Path DerivationGoal::openLogFile()
/* Create a log file. */ /* Create a log file. */
Path logDir; Path logDir;
if (auto localStore = dynamic_cast<LocalStore *>(&worker.store)) if (auto localStore = dynamic_cast<LocalFSStore *>(&worker.store))
logDir = localStore->logDir; logDir = localStore->logDir;
else else
logDir = settings.nixLogDir; logDir = settings.nixLogDir;

View file

@ -121,9 +121,9 @@ inline bool LocalDerivationGoal::needsHashRewrite()
} }
LocalStore & LocalDerivationGoal::getLocalStore() LocalFSStore & LocalDerivationGoal::getLocalFSStore()
{ {
auto p = dynamic_cast<LocalStore *>(&worker.store); auto p = dynamic_cast<LocalFSStore *>(&worker.store);
assert(p); assert(p);
return *p; return *p;
} }
@ -204,7 +204,7 @@ void LocalDerivationGoal::tryLocalBuild()
useChroot = derivationType->isSandboxed() && !noChroot; useChroot = derivationType->isSandboxed() && !noChroot;
} }
auto & localStore = getLocalStore(); auto & localStore = getLocalFSStore();
if (localStore.storeDir != localStore.realStoreDir.get()) { if (localStore.storeDir != localStore.realStoreDir.get()) {
#if __linux__ #if __linux__
useChroot = true; useChroot = true;
@ -343,7 +343,7 @@ bool LocalDerivationGoal::cleanupDecideWhetherDiskFull()
so, we don't mark this build as a permanent failure. */ so, we don't mark this build as a permanent failure. */
#if HAVE_STATVFS #if HAVE_STATVFS
{ {
auto & localStore = getLocalStore(); auto & localStore = getLocalFSStore();
uint64_t required = 8ULL * 1024 * 1024; // FIXME: make configurable uint64_t required = 8ULL * 1024 * 1024; // FIXME: make configurable
struct statvfs st; struct statvfs st;
if (statvfs(localStore.realStoreDir.get().c_str(), &st) == 0 && if (statvfs(localStore.realStoreDir.get().c_str(), &st) == 0 &&
@ -1223,16 +1223,16 @@ struct RestrictedStoreConfig : virtual LocalFSStoreConfig
const std::string name() { return "Restricted Store"; } const std::string name() { return "Restricted Store"; }
}; };
/* A wrapper around LocalStore that only allows building/querying of /* A wrapper around LocalFSStore that only allows building/querying of
paths that are in the input closures of the build or were added via paths that are in the input closures of the build or were added via
recursive Nix calls. */ recursive Nix calls. */
struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual IndirectRootStore, public virtual GcStore struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual IndirectRootStore, public virtual GcStore
{ {
ref<LocalStore> next; ref<LocalFSStore> next;
LocalDerivationGoal & goal; LocalDerivationGoal & goal;
RestrictedStore(const Params & params, ref<LocalStore> next, LocalDerivationGoal & goal) RestrictedStore(const Params & params, ref<LocalFSStore> next, LocalDerivationGoal & goal)
: StoreConfig(params) : StoreConfig(params)
, LocalFSStoreConfig(params) , LocalFSStoreConfig(params)
, RestrictedStoreConfig(params) , RestrictedStoreConfig(params)
@ -1459,12 +1459,12 @@ void LocalDerivationGoal::startDaemon()
Store::Params params; Store::Params params;
params["path-info-cache-size"] = "0"; params["path-info-cache-size"] = "0";
params["store"] = worker.store.storeDir; params["store"] = worker.store.storeDir;
if (auto & optRoot = getLocalStore().rootDir.get()) if (auto & optRoot = getLocalFSStore().rootDir.get())
params["root"] = *optRoot; params["root"] = *optRoot;
params["state"] = "/no-such-path"; params["state"] = "/no-such-path";
params["log"] = "/no-such-path"; params["log"] = "/no-such-path";
auto store = make_ref<RestrictedStore>(params, auto store = make_ref<RestrictedStore>(params,
ref<LocalStore>(std::dynamic_pointer_cast<LocalStore>(worker.store.shared_from_this())), ref<LocalFSStore>(std::dynamic_pointer_cast<LocalFSStore>(worker.store.shared_from_this())),
*this); *this);
addedPaths.clear(); addedPaths.clear();
@ -2632,7 +2632,7 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
} }
} }
auto & localStore = getLocalStore(); auto & localStore = getLocalFSStore();
if (buildMode == bmCheck) { if (buildMode == bmCheck) {
@ -2709,7 +2709,7 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
paths referenced by each of them. If there are cycles in the paths referenced by each of them. If there are cycles in the
outputs, this will fail. */ outputs, this will fail. */
{ {
auto & localStore = getLocalStore(); auto & localStore = getLocalFSStore();
ValidPathInfos infos2; ValidPathInfos infos2;
for (auto & [outputName, newInfo] : infos) { for (auto & [outputName, newInfo] : infos) {
@ -2754,7 +2754,7 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
void LocalDerivationGoal::signRealisation(Realisation & realisation) void LocalDerivationGoal::signRealisation(Realisation & realisation)
{ {
getLocalStore().signRealisation(realisation); getLocalFSStore().signRealisation(realisation);
} }

View file

@ -2,14 +2,14 @@
///@file ///@file
#include "derivation-goal.hh" #include "derivation-goal.hh"
#include "local-store.hh" #include "local-fs-store.hh"
#include "processes.hh" #include "processes.hh"
namespace nix { namespace nix {
struct LocalDerivationGoal : public DerivationGoal struct LocalDerivationGoal : public DerivationGoal
{ {
LocalStore & getLocalStore(); LocalFSStore & getLocalFSStore();
/** /**
* User selected for running the builder. * User selected for running the builder.

View file

@ -3,6 +3,8 @@
#include "substitution-goal.hh" #include "substitution-goal.hh"
#include "drv-output-substitution-goal.hh" #include "drv-output-substitution-goal.hh"
#include "local-derivation-goal.hh" #include "local-derivation-goal.hh"
// Just for `autoGC`, which should have own interface, don't add more usage!
#include "local-store.hh"
#include "hook-instance.hh" #include "hook-instance.hh"
#include "signals.hh" #include "signals.hh"
@ -64,7 +66,7 @@ std::shared_ptr<DerivationGoal> Worker::makeDerivationGoal(const StorePath & drv
const OutputsSpec & wantedOutputs, BuildMode buildMode) const OutputsSpec & wantedOutputs, BuildMode buildMode)
{ {
return makeDerivationGoalCommon(drvPath, wantedOutputs, [&]() -> std::shared_ptr<DerivationGoal> { return makeDerivationGoalCommon(drvPath, wantedOutputs, [&]() -> std::shared_ptr<DerivationGoal> {
return !dynamic_cast<LocalStore *>(&store) return !dynamic_cast<LocalFSStore *>(&store)
? std::make_shared</* */DerivationGoal>(drvPath, wantedOutputs, *this, buildMode) ? std::make_shared</* */DerivationGoal>(drvPath, wantedOutputs, *this, buildMode)
: std::make_shared<LocalDerivationGoal>(drvPath, wantedOutputs, *this, buildMode); : std::make_shared<LocalDerivationGoal>(drvPath, wantedOutputs, *this, buildMode);
}); });
@ -75,7 +77,7 @@ std::shared_ptr<DerivationGoal> Worker::makeBasicDerivationGoal(const StorePath
const BasicDerivation & drv, const OutputsSpec & wantedOutputs, BuildMode buildMode) const BasicDerivation & drv, const OutputsSpec & wantedOutputs, BuildMode buildMode)
{ {
return makeDerivationGoalCommon(drvPath, wantedOutputs, [&]() -> std::shared_ptr<DerivationGoal> { return makeDerivationGoalCommon(drvPath, wantedOutputs, [&]() -> std::shared_ptr<DerivationGoal> {
return !dynamic_cast<LocalStore *>(&store) return !dynamic_cast<LocalFSStore *>(&store)
? std::make_shared</* */DerivationGoal>(drvPath, drv, wantedOutputs, *this, buildMode) ? std::make_shared</* */DerivationGoal>(drvPath, drv, wantedOutputs, *this, buildMode)
: std::make_shared<LocalDerivationGoal>(drvPath, drv, wantedOutputs, *this, buildMode); : std::make_shared<LocalDerivationGoal>(drvPath, drv, wantedOutputs, *this, buildMode);
}); });

View file

@ -71,6 +71,40 @@ public:
std::optional<std::string> getBuildLogExact(const StorePath & path) override; std::optional<std::string> getBuildLogExact(const StorePath & path) override;
/**
* @todo this was moved to `LocalFSStore` from `LocalStore` because
* building needed it. Instead of just blindly moving it, we should
* should consider the division of labor and trust between the
* builder and the store.
*/
virtual void registerValidPaths(const ValidPathInfos & infos)
{ unsupported("registerValidPaths"); }
/**
* Optimise a single store path. Optionally, test the encountered
* symlinks for corruption.
*
* @todo this was moved to `LocalFSStore` from `LocalStore` because
* building needed it. Instead of just blindly moving it, we should
* should consider the division of labor and trust between the
* builder and the store.
*/
virtual void optimisePath(const Path & path, RepairFlag repair)
{ unsupported("optimisePath"); }
/**
* Add signatures to a ValidPathInfo or Realisation using the secret keys
* specified by the secret-key-files option.
*
* @todo this was moved to `LocalFSStore` from `LocalStore` because
* building needed it. Instead of just blindly moving it, we should
* should consider the division of labor and trust between the
* builder and the store.
*/
virtual void signPathInfo(ValidPathInfo & info)
{ unsupported("signPathInfo"); }
virtual void signRealisation(Realisation &)
{ unsupported("signRealisation"); }
}; };
} }

View file

@ -237,11 +237,7 @@ public:
void optimiseStore() override; void optimiseStore() override;
/** void optimisePath(const Path & path, RepairFlag repair) override;
* Optimise a single store path. Optionally, test the encountered
* symlinks for corruption.
*/
void optimisePath(const Path & path, RepairFlag repair);
bool verifyStore(bool checkContents, RepairFlag repair) override; bool verifyStore(bool checkContents, RepairFlag repair) override;
@ -255,7 +251,7 @@ public:
*/ */
void registerValidPath(const ValidPathInfo & info); void registerValidPath(const ValidPathInfo & info);
void registerValidPaths(const ValidPathInfos & infos); void registerValidPaths(const ValidPathInfos & infos) override;
unsigned int getProtocol() override; unsigned int getProtocol() override;
@ -343,12 +339,8 @@ private:
bool isValidPath_(State & state, const StorePath & path); bool isValidPath_(State & state, const StorePath & path);
void queryReferrers(State & state, const StorePath & path, StorePathSet & referrers); void queryReferrers(State & state, const StorePath & path, StorePathSet & referrers);
/** void signPathInfo(ValidPathInfo & info) override;
* Add signatures to a ValidPathInfo or Realisation using the secret keys void signRealisation(Realisation &) override;
* specified by the secret-key-files option.
*/
void signPathInfo(ValidPathInfo & info);
void signRealisation(Realisation &);
// XXX: Make a generic `Store` method // XXX: Make a generic `Store` method
ContentAddress hashCAPath( ContentAddress hashCAPath(