diff options
Diffstat (limited to 'nix/libstore')
-rw-r--r-- | nix/libstore/build.cc | 59 | ||||
-rw-r--r-- | nix/libstore/store-api.cc | 2 |
2 files changed, 50 insertions, 11 deletions
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc index d23c0944a4..43a8a37184 100644 --- a/nix/libstore/build.cc +++ b/nix/libstore/build.cc @@ -1301,6 +1301,34 @@ void replaceValidPath(const Path & storePath, const Path tmpPath) MakeError(NotDeterministic, BuildError) +/* Recursively make the file permissions of a path safe for exposure to + arbitrary users, but without canonicalising its permissions, timestamp, and + user. Throw an exception if a file type that isn't explicitly known to be + safe is found. */ +static void secureFilePerms(Path path) +{ + struct stat st; + if (lstat(path.c_str(), &st)) return; + + switch(st.st_mode & S_IFMT) { + case S_IFLNK: + return; + + case S_IFDIR: + for (auto & i : readDirectory(path)) { + secureFilePerms(path + "/" + i.name); + } + /* FALLTHROUGH */ + + case S_IFREG: + chmod(path.c_str(), (st.st_mode & ~S_IFMT) & ~(S_ISUID | S_ISGID | S_IWOTH)); + break; + + default: + throw Error(format("file `%1%' has an unsupported type") % path); + } +} + void DerivationGoal::buildDone() { trace("build done"); @@ -1372,8 +1400,14 @@ void DerivationGoal::buildDone() build failures. */ if (useChroot && buildMode == bmNormal) foreach (PathSet::iterator, i, missingPaths) - if (pathExists(chrootRootDir + *i)) + if (pathExists(chrootRootDir + *i)) { + try { + secureFilePerms(chrootRootDir + *i); rename((chrootRootDir + *i).c_str(), i->c_str()); + } catch(Error & e) { + printMsg(lvlError, e.msg()); + } + } if (diskFull) printMsg(lvlError, "note: build failure may have been caused by lack of free disk space"); @@ -2335,15 +2369,6 @@ void DerivationGoal::registerOutputs() Path actualPath = path; if (useChroot) { actualPath = chrootRootDir + path; - if (pathExists(actualPath)) { - /* Move output paths from the chroot to the store. */ - if (buildMode == bmRepair) - replaceValidPath(path, actualPath); - else - if (buildMode != bmCheck && rename(actualPath.c_str(), path.c_str()) == -1) - throw SysError(format("moving build output `%1%' from the chroot to the store") % path); - } - if (buildMode != bmCheck) actualPath = path; } else { Path redirected = redirectedOutputs[path]; if (buildMode == bmRepair @@ -2429,6 +2454,20 @@ void DerivationGoal::registerOutputs() canonicalisePathMetaData(actualPath, buildUser.enabled() && !rewritten ? buildUser.getUID() : -1, inodesSeen); + if (useChroot) { + if (pathExists(actualPath)) { + /* Now that output paths have been canonicalized (in particular + there are no setuid files left), move them outside of the + chroot and to the store. */ + if (buildMode == bmRepair) + replaceValidPath(path, actualPath); + else + if (buildMode != bmCheck && rename(actualPath.c_str(), path.c_str()) == -1) + throw SysError(format("moving build output `%1%' from the chroot to the store") % path); + } + if (buildMode != bmCheck) actualPath = path; + } + /* For this output path, find the references to other paths contained in it. Compute the SHA-256 NAR hash at the same time. The hash is stored in the database so that we can diff --git a/nix/libstore/store-api.cc b/nix/libstore/store-api.cc index 781fb9e693..38a1403a71 100644 --- a/nix/libstore/store-api.cc +++ b/nix/libstore/store-api.cc @@ -61,7 +61,7 @@ void checkStoreName(const string & name) /* Disallow names starting with a dot for possible security reasons (e.g., "." and ".."). */ if (string(name, 0, 1) == ".") - throw Error(format("invalid name: `%1%'") % name); + throw Error(format("invalid name: `%1%' (can't begin with dot)") % name); foreach (string::const_iterator, i, name) if (!((*i >= 'A' && *i <= 'Z') || (*i >= 'a' && *i <= 'z') || |