From f8cd904e05b95c5a3ca7cf570c0503a25a2095ca Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Sat, 27 Mar 2004 17:58:04 +0000 Subject: [PATCH] * Disallow the Nix store or any of its parents from being symlinks. This is because the contents of these symlinks are not incorporated into the hashes of derivations, and could therefore cause a mismatch between the build system and the target system. E.g., if `/nix/store' is a symlink to `/data/nix/store', then a builder could expand this path and store the result. If on the target system `/nix/store' is not a symlink, or is a symlink that points somewhere else, we have a dangling pointer. The trigger for this change is that gcc 3.3.3 does exactly that (it applies realpath() to some files, such as libraries, which causes our impurity checker to bail out.) An annoying side-effect of this change is that it makes it harder to move the Nix store to a different file system. On Linux, bind mounts can be used instead of symlink for this purpose (e.g., `mount -o bind /data/nix/store /nix/store'). --- src/libmain/shared.cc | 35 +++++++++++++++++++++++++++++------ src/libutil/util.hh | 13 ++++++++----- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index a93d6cb501..42f17cf4ed 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -1,7 +1,10 @@ - #include #include +#include +#include +#include + extern "C" { #include } @@ -27,6 +30,22 @@ void setLogType(string lt) } +void checkStoreNotSymlink(Path path) +{ + struct stat st; + while (path.size()) { + if (lstat(path.c_str(), &st)) + throw SysError(format("getting status of `%1%'") % path); + if (S_ISLNK(st.st_mode)) + throw Error(format( + "the path `%1%' is a symlink; " + "this is not allowed for the Nix store and its parent directories") + % path); + path = dirOf(path); + } +} + + /* Initialize and reorder arguments, then call the actual argument processor. */ static void initAndRun(int argc, char * * argv) @@ -39,11 +58,15 @@ static void initAndRun(int argc, char * * argv) } /* Setup Nix paths. */ - nixStore = NIX_STORE_DIR; - nixDataDir = NIX_DATA_DIR; - nixLogDir = NIX_LOG_DIR; - nixStateDir = (string) NIX_STATE_DIR; - nixDBPath = (string) NIX_STATE_DIR + "/db"; + nixStore = canonPath(NIX_STORE_DIR); + nixDataDir = canonPath(NIX_DATA_DIR); + nixLogDir = canonPath(NIX_LOG_DIR); + nixStateDir = canonPath(NIX_STATE_DIR); + nixDBPath = canonPath(NIX_STATE_DIR) + "/db"; + + /* Check that the store directory and its parent are not + symlinks. */ + checkStoreNotSymlink(nixStore); /* Catch SIGINT. */ struct sigaction act, oact; diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 54673c28c6..1b0600006a 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -60,15 +60,18 @@ extern string thisSystem; is also canonicalised. */ Path absPath(Path path, Path dir = ""); -/* Canonicalise a path (as in realpath(3)). */ +/* Canonicalise a path by removing all `.' or `..' components and + double or trailing slashes. */ Path canonPath(const Path & path); -/* Return the directory part of the given path, i.e., everything - before the final `/'. */ +/* Return the directory part of the given canonical path, i.e., + everything before the final `/'. If the path is the root or an + immediate child thereof (e.g., `/foo'), this means an empty string + is returned. */ Path dirOf(const Path & path); -/* Return the base name of the given path, i.e., everything following - the final `/'. */ +/* Return the base name of the given canonical path, i.e., everything + following the final `/'. */ string baseNameOf(const Path & path); /* Return true iff the given path exists. */