aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2018-11-13 16:15:30 +0100
committerEelco Dolstra <edolstra@gmail.com>2018-11-13 16:15:30 +0100
commita0ef21262f4d5652bfb65cfacaec01d89c475a93 (patch)
tree6fd2c483dde9bb6f56ff989b6724d2a49679d74a /src
parent56f6e382be03b587c1f7260e16fce6622329d1a4 (diff)
Restore parent mount namespace before executing a child process
This ensures that they can't write to /nix/store. Fixes #2535.
Diffstat (limited to 'src')
-rw-r--r--src/libstore/local-store.cc2
-rw-r--r--src/libstore/ssh.cc3
-rw-r--r--src/libutil/util.cc23
-rw-r--r--src/libutil/util.hh9
-rwxr-xr-xsrc/nix-build/nix-build.cc4
-rw-r--r--src/nix/edit.cc5
-rw-r--r--src/nix/repl.cc2
-rw-r--r--src/nix/run.cc4
8 files changed, 48 insertions, 4 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 216f3417c..e1cb423d1 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -366,6 +366,8 @@ 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/libstore/ssh.cc b/src/libstore/ssh.cc
index 5e0e44935..cf133b57c 100644
--- a/src/libstore/ssh.cc
+++ b/src/libstore/ssh.cc
@@ -1,4 +1,5 @@
#include "ssh.hh"
+#include "affinity.hh"
namespace nix {
@@ -34,7 +35,9 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string
auto conn = std::make_unique<Connection>();
conn->sshPid = startProcess([&]() {
+ restoreAffinity();
restoreSignals();
+ restoreMountNamespace();
close(in.writeSide.get());
close(out.readSide.get());
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 259eaf0a0..6e4536e6e 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -936,6 +936,7 @@ pid_t startProcess(std::function<void()> fun, const ProcessOptions & options)
throw SysError("setting death signal");
#endif
restoreAffinity();
+ restoreMountNamespace();
fun();
} catch (std::exception & e) {
try {
@@ -1504,4 +1505,26 @@ std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()>
return std::unique_ptr<InterruptCallback>(res.release());
}
+static AutoCloseFD fdSavedMountNamespace;
+
+void saveMountNamespace()
+{
+#if __linux__
+ 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
+}
+
}
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index bda87bee4..2689cbd8b 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -514,4 +514,13 @@ typedef std::function<bool(const Path & path)> PathFilter;
extern PathFilter defaultPathFilter;
+/* 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();
+
+
}
diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc
index 618895d38..11ea3b1f7 100755
--- a/src/nix-build/nix-build.cc
+++ b/src/nix-build/nix-build.cc
@@ -401,8 +401,6 @@ static void _main(int argc, char * * argv)
} else
env[var.first] = var.second;
- restoreAffinity();
-
/* Run a shell using the derivation's environment. For
convenience, source $stdenv/setup to setup additional
environment variables and shell functions. Also don't
@@ -446,7 +444,9 @@ static void _main(int argc, char * * argv)
auto argPtrs = stringsToCharPtrs(args);
+ restoreAffinity();
restoreSignals();
+ restoreMountNamespace();
execvp(shell.c_str(), argPtrs.data());
diff --git a/src/nix/edit.cc b/src/nix/edit.cc
index c9671f76d..d8d5895bd 100644
--- a/src/nix/edit.cc
+++ b/src/nix/edit.cc
@@ -3,6 +3,7 @@
#include "eval.hh"
#include "attr-path.hh"
#include "progress-bar.hh"
+#include "affinity.hh"
#include <unistd.h>
@@ -72,6 +73,10 @@ struct CmdEdit : InstallableCommand
stopProgressBar();
+ restoreAffinity();
+ restoreSignals();
+ restoreMountNamespace();
+
execvp(args.front().c_str(), stringsToCharPtrs(args).data());
throw SysError("cannot run editor '%s'", editor);
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index 1bbe256b2..77898c632 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -285,6 +285,8 @@ static int runProgram(const string & program, const Strings & args)
if (pid == -1) throw SysError("forking");
if (pid == 0) {
restoreAffinity();
+ restoreSignals();
+ restoreMountNamespace();
execvp(program.c_str(), stringsToCharPtrs(args2).data());
_exit(1);
}
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 35b763345..129707298 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -153,9 +153,9 @@ struct CmdRun : InstallablesCommand
stopProgressBar();
- restoreSignals();
-
restoreAffinity();
+ restoreSignals();
+ restoreMountNamespace();
/* If this is a diverted store (i.e. its "logical" location
(typically /nix/store) differs from its "physical" location