diff options
author | Yorick van Pelt <yorick@yorickvanpelt.nl> | 2021-10-15 16:25:49 +0200 |
---|---|---|
committer | Yorick van Pelt <yorick@yorickvanpelt.nl> | 2021-10-15 16:25:49 +0200 |
commit | fcb8af550f5fca37458da0d9042a2b59523eb304 (patch) | |
tree | 050bde8ad2b73808860e9c94043a4532fae66bd2 /src/libutil/util.cc | |
parent | 130284b8508dad3c70e8160b15f3d62042fc730a (diff) |
Restore parent mount namespace in restoreProcessContext
This ensures any started processes can't write to /nix/store (except
during builds). This partially reverts 01d07b1e, which happened because
of #2646.
The problem was only happening after nix downloads anything, causing
me to suspect the download thread. The problem turns out to be:
"A process can't join a new mount namespace if it is sharing
filesystem-related attributes with another process", in this case this
process is the curl thread.
Ideally, we might kill it before spawning the shell process, but it's
inside a static variable in the getFileTransfer() function. So
instead, stop it from sharing FS state using unshare(). A strategy
such as the one from #5057 (single-threaded chroot helper binary) is
also very much on the table.
Fixes #4337.
Diffstat (limited to 'src/libutil/util.cc')
-rw-r--r-- | src/libutil/util.cc | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 563a72c12..a5e961c1e 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -1629,10 +1629,34 @@ void setStackSize(size_t stackSize) } #endif } +static AutoCloseFD fdSavedMountNamespace; -void restoreProcessContext() +void saveMountNamespace() +{ +#if __linux__ + static std::once_flag done; + std::call_once(done, []() { + fdSavedMountNamespace = open("/proc/self/ns/mnt", O_RDONLY); + if (!fdSavedMountNamespace) + throw SysError("saving parent mount namespace"); + }); +#endif +} + +void restoreMountNamespace() +{ +#if __linux__ + if (fdSavedMountNamespace && setns(fdSavedMountNamespace.get(), CLONE_NEWNS) == -1) + throw SysError("restoring parent mount namespace"); +#endif +} + +void restoreProcessContext(bool restoreMounts) { restoreSignals(); + if (restoreMounts) { + restoreMountNamespace(); + } restoreAffinity(); @@ -1766,7 +1790,7 @@ void commonChildInit(Pipe & logPipe) logger = makeSimpleLogger(); const static string pathNullDevice = "/dev/null"; - restoreProcessContext(); + restoreProcessContext(false); /* Put the child in a separate session (and thus a separate process group) so that it has no controlling terminal (meaning |