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.
This commit is contained in:
parent
76e88871b2
commit
b9124a5c33
2 changed files with 41 additions and 0 deletions
|
@ -20,6 +20,11 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#if HAVE_UNSHARE
|
||||||
|
#include <sched.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -292,6 +297,8 @@ LocalStore::LocalStore(bool reserveSpace)
|
||||||
}
|
}
|
||||||
|
|
||||||
else openDB(false);
|
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 */
|
const time_t mtimeStore = 1; /* 1 second into the epoch */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -228,6 +228,8 @@ private:
|
||||||
|
|
||||||
void openDB(bool create);
|
void openDB(bool create);
|
||||||
|
|
||||||
|
void makeStoreWritable();
|
||||||
|
|
||||||
unsigned long long queryValidPathId(const Path & path);
|
unsigned long long queryValidPathId(const Path & path);
|
||||||
|
|
||||||
unsigned long long addValidPath(const ValidPathInfo & info, bool checkOutputs = true);
|
unsigned long long addValidPath(const ValidPathInfo & info, bool checkOutputs = true);
|
||||||
|
|
Loading…
Reference in a new issue