aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2012-09-19 15:45:29 -0400
committerEelco Dolstra <eelco.dolstra@logicblox.com>2012-09-19 15:45:29 -0400
commitb9124a5c336fd231adaa548cf5be311731847848 (patch)
tree4512ebc47414036212e8b1e895147f6300124df4 /src/libstore
parent76e88871b21c47c0216e160a5fb926f763ba64fe (diff)
Support having /nix/store as a read-only bind mount
It turns out that the immutable bit doesn't work all that well. A better way is to make the entire Nix store a read-only bind mount, i.e. by doing $ mount --bind /nix/store /nix/store $ mount -o remount,ro,bind /nix/store (This would typically done in an early boot script, before anything from /nix/store is used.) Since Nix needs to be able to write to the Nix store, it now detects if /nix/store is a read-only bind mount and then makes it writable in a private mount namespace.
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/local-store.cc39
-rw-r--r--src/libstore/local-store.hh2
2 files changed, 41 insertions, 0 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 085e662ed..bb755b821 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -20,6 +20,11 @@
#include <stdio.h>
#include <time.h>
+#if HAVE_UNSHARE
+#include <sched.h>
+#include <sys/mount.h>
+#endif
+
#include <sqlite3.h>
@@ -292,6 +297,8 @@ LocalStore::LocalStore(bool reserveSpace)
}
else openDB(false);
+
+ makeStoreWritable();
}
@@ -411,6 +418,38 @@ void LocalStore::openDB(bool create)
}
+/* To improve purity, users may want to make the Nix store a read-only
+ bind mount. So make the Nix store writable for this process. */
+void LocalStore::makeStoreWritable()
+{
+#if HAVE_UNSHARE
+ if (getuid() != 0) return;
+
+ if (!pathExists("/proc/self/mountinfo")) return;
+
+ /* Check if /nix/store is a read-only bind mount. */
+ bool found = false;
+ Strings mounts = tokenizeString<Strings>(readFile("/proc/self/mountinfo", true), "\n");
+ foreach (Strings::iterator, i, mounts) {
+ vector<string> fields = tokenizeString<vector<string> >(*i, " ");
+ if (fields.at(3) == "/" || fields.at(4) != settings.nixStore) continue;
+ Strings options = tokenizeString<Strings>(fields.at(5), ",");
+ if (std::find(options.begin(), options.end(), "ro") == options.end()) continue;
+ found = true;
+ break;
+ }
+
+ if (!found) return;
+
+ if (unshare(CLONE_NEWNS) == -1)
+ throw SysError("setting up a private mount namespace");
+
+ if (mount(0, settings.nixStore.c_str(), 0, MS_REMOUNT | MS_BIND, 0) == -1)
+ throw SysError(format("remounting %1% writable") % settings.nixStore);
+#endif
+}
+
+
const time_t mtimeStore = 1; /* 1 second into the epoch */
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index d2b13d6a9..8899873a7 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -228,6 +228,8 @@ private:
void openDB(bool create);
+ void makeStoreWritable();
+
unsigned long long queryValidPathId(const Path & path);
unsigned long long addValidPath(const ValidPathInfo & info, bool checkOutputs = true);