Skip to content

Commit 2cfd031

Browse files
authored
Merge pull request #12662 from obsidiansystems/local-derivation-goal-hide
Local derivation goal hide
2 parents e4bda20 + 7f2b7b8 commit 2cfd031

File tree

7 files changed

+338
-303
lines changed

7 files changed

+338
-303
lines changed

src/libstore/build/worker.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ std::shared_ptr<DerivationGoal> Worker::makeDerivationGoal(const StorePath & drv
6868
return
6969
#ifndef _WIN32 // TODO Enable building on Windows
7070
dynamic_cast<LocalStore *>(&store)
71-
? std::make_shared<LocalDerivationGoal>(drvPath, wantedOutputs, *this, buildMode)
71+
? makeLocalDerivationGoal(drvPath, wantedOutputs, *this, buildMode)
7272
:
7373
#endif
7474
std::make_shared</* */DerivationGoal>(drvPath, wantedOutputs, *this, buildMode);
@@ -82,7 +82,7 @@ std::shared_ptr<DerivationGoal> Worker::makeBasicDerivationGoal(const StorePath
8282
return
8383
#ifndef _WIN32 // TODO Enable building on Windows
8484
dynamic_cast<LocalStore *>(&store)
85-
? std::make_shared<LocalDerivationGoal>(drvPath, drv, wantedOutputs, *this, buildMode)
85+
? makeLocalDerivationGoal(drvPath, drv, wantedOutputs, *this, buildMode)
8686
:
8787
#endif
8888
std::make_shared</* */DerivationGoal>(drvPath, drv, wantedOutputs, *this, buildMode);

src/libstore/local-store.cc

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,20 +1582,6 @@ void LocalStore::addSignatures(const StorePath & storePath, const StringSet & si
15821582
}
15831583

15841584

1585-
void LocalStore::signPathInfo(ValidPathInfo & info)
1586-
{
1587-
// FIXME: keep secret keys in memory.
1588-
1589-
auto secretKeyFiles = settings.secretKeyFiles;
1590-
1591-
for (auto & secretKeyFile : secretKeyFiles.get()) {
1592-
SecretKey secretKey(readFile(secretKeyFile));
1593-
LocalSigner signer(std::move(secretKey));
1594-
info.sign(*this, signer);
1595-
}
1596-
}
1597-
1598-
15991585
std::optional<std::pair<int64_t, Realisation>> LocalStore::queryRealisationCore_(
16001586
LocalStore::State & state,
16011587
const DrvOutput & id)

src/libstore/local-store.hh

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -396,12 +396,6 @@ private:
396396
bool isValidPath_(State & state, const StorePath & path);
397397
void queryReferrers(State & state, const StorePath & path, StorePathSet & referrers);
398398

399-
/**
400-
* Add signatures to a ValidPathInfo or Realisation using the secret keys
401-
* specified by the ‘secret-key-files’ option.
402-
*/
403-
void signPathInfo(ValidPathInfo & info);
404-
405399
void addBuildLog(const StorePath & drvPath, std::string_view log) override;
406400

407401
friend struct LocalDerivationGoal;

src/libstore/store-api.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,21 @@ Derivation Store::readDerivation(const StorePath & drvPath)
12741274
Derivation Store::readInvalidDerivation(const StorePath & drvPath)
12751275
{ return readDerivationCommon(*this, drvPath, false); }
12761276

1277+
1278+
void Store::signPathInfo(ValidPathInfo & info)
1279+
{
1280+
// FIXME: keep secret keys in memory.
1281+
1282+
auto secretKeyFiles = settings.secretKeyFiles;
1283+
1284+
for (auto & secretKeyFile : secretKeyFiles.get()) {
1285+
SecretKey secretKey(readFile(secretKeyFile));
1286+
LocalSigner signer(std::move(secretKey));
1287+
info.sign(*this, signer);
1288+
}
1289+
}
1290+
1291+
12771292
void Store::signRealisation(Realisation & realisation)
12781293
{
12791294
// FIXME: keep secret keys in memory.

src/libstore/store-api.hh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,12 @@ public:
622622
virtual void addSignatures(const StorePath & storePath, const StringSet & sigs)
623623
{ unsupported("addSignatures"); }
624624

625+
/**
626+
* Add signatures to a ValidPathInfo or Realisation using the secret keys
627+
* specified by the ‘secret-key-files’ option.
628+
*/
629+
void signPathInfo(ValidPathInfo & info);
630+
625631
void signRealisation(Realisation &);
626632

627633
/* Utility functions. */

src/libstore/unix/build/local-derivation-goal.cc

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include "local-derivation-goal.hh"
2+
#include "local-store.hh"
3+
#include "processes.hh"
24
#include "indirect-root-store.hh"
35
#include "hook-instance.hh"
46
#include "worker.hh"
@@ -73,6 +75,302 @@ extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags,
7375

7476
namespace nix {
7577

78+
struct LocalDerivationGoal : public DerivationGoal
79+
{
80+
LocalStore & getLocalStore();
81+
82+
/**
83+
* User selected for running the builder.
84+
*/
85+
std::unique_ptr<UserLock> buildUser;
86+
87+
/**
88+
* The process ID of the builder.
89+
*/
90+
Pid pid;
91+
92+
/**
93+
* The cgroup of the builder, if any.
94+
*/
95+
std::optional<Path> cgroup;
96+
97+
/**
98+
* The temporary directory used for the build.
99+
*/
100+
Path tmpDir;
101+
102+
/**
103+
* The top-level temporary directory. `tmpDir` is either equal to
104+
* or a child of this directory.
105+
*/
106+
Path topTmpDir;
107+
108+
/**
109+
* The path of the temporary directory in the sandbox.
110+
*/
111+
Path tmpDirInSandbox;
112+
113+
/**
114+
* Master side of the pseudoterminal used for the builder's
115+
* standard output/error.
116+
*/
117+
AutoCloseFD builderOut;
118+
119+
/**
120+
* Pipe for synchronising updates to the builder namespaces.
121+
*/
122+
Pipe userNamespaceSync;
123+
124+
/**
125+
* The mount namespace and user namespace of the builder, used to add additional
126+
* paths to the sandbox as a result of recursive Nix calls.
127+
*/
128+
AutoCloseFD sandboxMountNamespace;
129+
AutoCloseFD sandboxUserNamespace;
130+
131+
/**
132+
* On Linux, whether we're doing the build in its own user
133+
* namespace.
134+
*/
135+
bool usingUserNamespace = true;
136+
137+
/**
138+
* Whether we're currently doing a chroot build.
139+
*/
140+
bool useChroot = false;
141+
142+
/**
143+
* The root of the chroot environment.
144+
*/
145+
Path chrootRootDir;
146+
147+
/**
148+
* RAII object to delete the chroot directory.
149+
*/
150+
std::shared_ptr<AutoDelete> autoDelChroot;
151+
152+
/**
153+
* Stuff we need to pass to initChild().
154+
*/
155+
struct ChrootPath {
156+
Path source;
157+
bool optional;
158+
ChrootPath(Path source = "", bool optional = false)
159+
: source(source), optional(optional)
160+
{ }
161+
};
162+
typedef map<Path, ChrootPath> PathsInChroot; // maps target path to source path
163+
PathsInChroot pathsInChroot;
164+
165+
typedef map<std::string, std::string> Environment;
166+
Environment env;
167+
168+
/**
169+
* Hash rewriting.
170+
*/
171+
StringMap inputRewrites, outputRewrites;
172+
typedef map<StorePath, StorePath> RedirectedOutputs;
173+
RedirectedOutputs redirectedOutputs;
174+
175+
/**
176+
* The output paths used during the build.
177+
*
178+
* - Input-addressed derivations or fixed content-addressed outputs are
179+
* sometimes built when some of their outputs already exist, and can not
180+
* be hidden via sandboxing. We use temporary locations instead and
181+
* rewrite after the build. Otherwise the regular predetermined paths are
182+
* put here.
183+
*
184+
* - Floating content-addressing derivations do not know their final build
185+
* output paths until the outputs are hashed, so random locations are
186+
* used, and then renamed. The randomness helps guard against hidden
187+
* self-references.
188+
*/
189+
OutputPathMap scratchOutputs;
190+
191+
uid_t sandboxUid() { return usingUserNamespace ? (!buildUser || buildUser->getUIDCount() == 1 ? 1000 : 0) : buildUser->getUID(); }
192+
gid_t sandboxGid() { return usingUserNamespace ? (!buildUser || buildUser->getUIDCount() == 1 ? 100 : 0) : buildUser->getGID(); }
193+
194+
const static Path homeDir;
195+
196+
/**
197+
* The recursive Nix daemon socket.
198+
*/
199+
AutoCloseFD daemonSocket;
200+
201+
/**
202+
* The daemon main thread.
203+
*/
204+
std::thread daemonThread;
205+
206+
/**
207+
* The daemon worker threads.
208+
*/
209+
std::vector<std::thread> daemonWorkerThreads;
210+
211+
/**
212+
* Paths that were added via recursive Nix calls.
213+
*/
214+
StorePathSet addedPaths;
215+
216+
/**
217+
* Realisations that were added via recursive Nix calls.
218+
*/
219+
std::set<DrvOutput> addedDrvOutputs;
220+
221+
/**
222+
* Recursive Nix calls are only allowed to build or realize paths
223+
* in the original input closure or added via a recursive Nix call
224+
* (so e.g. you can't do 'nix-store -r /nix/store/<bla>' where
225+
* /nix/store/<bla> is some arbitrary path in a binary cache).
226+
*/
227+
bool isAllowed(const StorePath & path)
228+
{
229+
return inputPaths.count(path) || addedPaths.count(path);
230+
}
231+
bool isAllowed(const DrvOutput & id)
232+
{
233+
return addedDrvOutputs.count(id);
234+
}
235+
236+
bool isAllowed(const DerivedPath & req);
237+
238+
friend struct RestrictedStore;
239+
240+
using DerivationGoal::DerivationGoal;
241+
242+
virtual ~LocalDerivationGoal() override;
243+
244+
/**
245+
* Whether we need to perform hash rewriting if there are valid output paths.
246+
*/
247+
bool needsHashRewrite();
248+
249+
/**
250+
* The additional states.
251+
*/
252+
Goal::Co tryLocalBuild() override;
253+
254+
/**
255+
* Start building a derivation.
256+
*/
257+
void startBuilder();
258+
259+
/**
260+
* Fill in the environment for the builder.
261+
*/
262+
void initEnv();
263+
264+
/**
265+
* Process messages send by the sandbox initialization.
266+
*/
267+
void processSandboxSetupMessages();
268+
269+
/**
270+
* Setup tmp dir location.
271+
*/
272+
void initTmpDir();
273+
274+
/**
275+
* Write a JSON file containing the derivation attributes.
276+
*/
277+
void writeStructuredAttrs();
278+
279+
/**
280+
* Start an in-process nix daemon thread for recursive-nix.
281+
*/
282+
void startDaemon();
283+
284+
/**
285+
* Stop the in-process nix daemon thread.
286+
* @see startDaemon
287+
*/
288+
void stopDaemon();
289+
290+
/**
291+
* Add 'path' to the set of paths that may be referenced by the
292+
* outputs, and make it appear in the sandbox.
293+
*/
294+
void addDependency(const StorePath & path);
295+
296+
/**
297+
* Make a file owned by the builder.
298+
*/
299+
void chownToBuilder(const Path & path);
300+
301+
/**
302+
* Run the builder's process.
303+
*/
304+
void runChild();
305+
306+
/**
307+
* Check that the derivation outputs all exist and register them
308+
* as valid.
309+
*/
310+
SingleDrvOutputs registerOutputs();
311+
312+
/**
313+
* Check that an output meets the requirements specified by the
314+
* 'outputChecks' attribute (or the legacy
315+
* '{allowed,disallowed}{References,Requisites}' attributes).
316+
*/
317+
void checkOutputs(const std::map<std::string, ValidPathInfo> & outputs);
318+
319+
bool isReadDesc(int fd) override;
320+
321+
/**
322+
* Delete the temporary directory, if we have one.
323+
*/
324+
void deleteTmpDir(bool force);
325+
326+
/**
327+
* Forcibly kill the child process, if any.
328+
*
329+
* Called by destructor, can't be overridden
330+
*/
331+
void killChild() override final;
332+
333+
/**
334+
* Kill any processes running under the build user UID or in the
335+
* cgroup of the build.
336+
*/
337+
void killSandbox(bool getStats);
338+
339+
bool cleanupDecideWhetherDiskFull();
340+
341+
/**
342+
* Create alternative path calculated from but distinct from the
343+
* input, so we can avoid overwriting outputs (or other store paths)
344+
* that already exist.
345+
*/
346+
StorePath makeFallbackPath(const StorePath & path);
347+
348+
/**
349+
* Make a path to another based on the output name along with the
350+
* derivation hash.
351+
*
352+
* @todo Add option to randomize, so we can audit whether our
353+
* rewrites caught everything
354+
*/
355+
StorePath makeFallbackPath(OutputNameView outputName);
356+
};
357+
358+
std::shared_ptr<DerivationGoal> makeLocalDerivationGoal(
359+
const StorePath & drvPath,
360+
const OutputsSpec & wantedOutputs, Worker & worker,
361+
BuildMode buildMode)
362+
{
363+
return std::make_shared<LocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
364+
}
365+
366+
std::shared_ptr<DerivationGoal> makeLocalDerivationGoal(
367+
const StorePath & drvPath, const BasicDerivation & drv,
368+
const OutputsSpec & wantedOutputs, Worker & worker,
369+
BuildMode buildMode)
370+
{
371+
return std::make_shared<LocalDerivationGoal>(drvPath, drv, wantedOutputs, worker, buildMode);
372+
}
373+
76374
void handleDiffHook(
77375
uid_t uid, uid_t gid,
78376
const Path & tryA, const Path & tryB,

0 commit comments

Comments
 (0)