aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libstore/filetransfer.cc8
-rw-r--r--src/libstore/local-store.cc1
-rw-r--r--src/libutil/util.cc28
-rw-r--r--src/libutil/util.hh10
4 files changed, 44 insertions, 3 deletions
diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc
index 37e17b397..4621a8217 100644
--- a/src/libstore/filetransfer.cc
+++ b/src/libstore/filetransfer.cc
@@ -544,6 +544,14 @@ struct curlFileTransfer : public FileTransfer
stopWorkerThread();
});
+#ifdef __linux__
+ /* Cause this thread to not share any FS attributes with the main thread,
+ because this causes setns() in restoreMountNamespace() to fail.
+ Ideally, this would happen in the std::thread() constructor. */
+ if (unshare(CLONE_FS) != 0)
+ throw SysError("unsharing filesystem state in download thread");
+#endif
+
std::map<CURL *, std::shared_ptr<TransferItem>> items;
bool quit = false;
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 225a19e1e..1cef50a40 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -504,6 +504,7 @@ void LocalStore::makeStoreWritable()
throw SysError("getting info about the Nix store mount point");
if (stat.f_flag & ST_RDONLY) {
+ saveMountNamespace();
if (unshare(CLONE_NEWNS) == -1)
throw SysError("setting up a private mount namespace");
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 7687e3e01..a6552ebca 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -1631,10 +1631,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();
@@ -1774,7 +1798,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
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 485ff4153..708e01cf8 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -300,7 +300,15 @@ void setStackSize(size_t stackSize);
/* Restore the original inherited Unix process context (such as signal
masks, stack size, CPU affinity). */
-void restoreProcessContext();
+void restoreProcessContext(bool restoreMounts = true);
+
+/* Save the current mount namespace. Ignored if called more than
+ once. */
+void saveMountNamespace();
+
+/* Restore the mount namespace saved by saveMountNamespace(). Ignored
+ if saveMountNamespace() was never called. */
+void restoreMountNamespace();
class ExecError : public Error