aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHartmut Goebel <h.goebel@crazy-compilers.com>2016-11-21 19:49:12 +0100
committerHartmut Goebel <h.goebel@crazy-compilers.com>2016-12-09 15:46:09 +0100
commit2608e40988ba8cf51723fe0d21bdedf6b3997c9c (patch)
treea50081f9bc00670849296fd8f799b9a5c13ba4c9
parent43e8824d3cd3ff53671167ab9b41f0094458a4d6 (diff)
downloadguix-2608e40988ba8cf51723fe0d21bdedf6b3997c9c.tar.gz
guix-2608e40988ba8cf51723fe0d21bdedf6b3997c9c.zip
daemon: Set ownership of kept build directories to the calling user.
Fixes <http://bugs.gnu.org/15890>. * nix/libstore/globals.hh (Settings) Add clientUid and clientGid. * nix/nix-daemon/nix-daemon.cc (daemonLoop] Store UID and GID of the caller in settings. * nix/libstore/build.cc (_chown): New function. (DerivationGoal::deleteTmpDir): Use it, change ownership of build directory if it is kept and the new owner is not root.
-rw-r--r--nix/libstore/build.cc21
-rw-r--r--nix/libstore/globals.hh6
-rw-r--r--nix/nix-daemon/nix-daemon.cc12
3 files changed, 39 insertions, 0 deletions
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 889ee3d2bd..e823001788 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -2631,6 +2631,21 @@ void DerivationGoal::closeLogFile()
}
+static void _chown(const Path & path, uid_t uid, gid_t gid)
+{
+ checkInterrupt();
+
+ if (lchown(path.c_str(), uid, gid) == -1) {
+ throw SysError(format("change owner and group of `%1%'") % path);
+ }
+ struct stat st = lstat(path);
+ if (S_ISDIR(st.st_mode)) {
+ for (auto & i : readDirectory(path))
+ _chown(path + "/" + i.name, uid, gid);
+ }
+}
+
+
void DerivationGoal::deleteTmpDir(bool force)
{
if (tmpDir != "") {
@@ -2639,6 +2654,12 @@ void DerivationGoal::deleteTmpDir(bool force)
format("note: keeping build directory `%2%'")
% drvPath % tmpDir);
chmod(tmpDir.c_str(), 0755);
+ // Change the ownership if clientUid is set. Never change the
+ // ownership or the group to "root" for security reasons.
+ if (settings.clientUid != (uid_t) -1 && settings.clientUid != 0) {
+ _chown(tmpDir, settings.clientUid,
+ settings.clientGid != 0 ? settings.clientGid : -1);
+ }
}
else
deletePath(tmpDir);
diff --git a/nix/libstore/globals.hh b/nix/libstore/globals.hh
index 8c07e360f2..7beb1a55ca 100644
--- a/nix/libstore/globals.hh
+++ b/nix/libstore/globals.hh
@@ -70,6 +70,12 @@ struct Settings {
subgoal of the same goal) fails. */
bool keepGoing;
+ /* User and groud id of the client issuing the build request. Used to set
+ the owner and group of the kept temporary directories of failed
+ builds. */
+ uid_t clientUid;
+ gid_t clientGid;
+
/* Whether, if we cannot realise the known closure corresponding
to a derivation, we should try to normalise the derivation
instead. */
diff --git a/nix/nix-daemon/nix-daemon.cc b/nix/nix-daemon/nix-daemon.cc
index 682f9a2b5b..47b67d5863 100644
--- a/nix/nix-daemon/nix-daemon.cc
+++ b/nix/nix-daemon/nix-daemon.cc
@@ -960,6 +960,18 @@ static void daemonLoop()
strncpy(argvSaved[1], processName.c_str(), strlen(argvSaved[1]));
}
+#if defined(SO_PEERCRED)
+ /* Store the client's user and group for this connection. This
+ has to be done in the forked process since it is per
+ connection. */
+ settings.clientUid = cred.uid;
+ settings.clientGid = cred.gid;
+#else
+ /* Setting these to -1 means: do not change */
+ settings.clientUid = (uid_t) -1;
+ settings.clientGid = (gid_t) -1;
+#endif
+
/* Handle the connection. */
from.fd = remote;
to.fd = remote;