about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorGraham Christensen <graham@grahamc.com>2019-05-11T00·59-0400
committerGraham Christensen <graham@grahamc.com>2019-05-12T17·17-0400
commit6df61db0600ca73ccd51e3e5bec5312a04e99da1 (patch)
tree66de67c9b1ce6b90ea9d643d95d9a9d750b3c376 /src
parentc78686e411e0a14cff51836fe6c35d7584171df3 (diff)
diff hook: execute as the build user, and pass the temp dir
Diffstat (limited to 'src')
-rw-r--r--src/libstore/build.cc41
-rw-r--r--src/libutil/util.cc4
-rw-r--r--src/libutil/util.hh2
3 files changed, 33 insertions, 14 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 026828c535ca..f38d2eaa0cde 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -461,17 +461,26 @@ static void commonChildInit(Pipe & logPipe)
     close(fdDevNull);
 }
 
-void handleDiffHook(Path tryA, Path tryB, Path drvPath)
+void handleDiffHook(bool allowVfork, uid_t uid, uid_t gid, Path tryA, Path tryB, Path drvPath, Path tmpDir)
 {
     auto diffHook = settings.diffHook;
     if (diffHook != "" && settings.runDiffHook) {
-        try {
-            auto diff = runProgram(diffHook, true, {tryA, tryB, drvPath});
-            if (diff != "")
-                printError(chomp(diff));
-        } catch (Error & error) {
-            printError("diff hook execution failed: %s", error.what());
-        }
+        auto wrapper = [&]() {
+            if (setgid(gid) == -1)
+                throw SysError("setgid failed");
+            if (setuid(uid) == -1)
+                throw SysError("setuid failed");
+
+            try {
+                auto diff = runProgram(diffHook, true, {tryA, tryB, drvPath, tmpDir});
+                if (diff != "")
+                    printError(chomp(diff));
+            } catch (Error & error) {
+                printError("diff hook execution failed: %s", error.what());
+            }
+        };
+
+        doFork(allowVfork, wrapper);
     }
 }
 
@@ -3197,14 +3206,18 @@ void DerivationGoal::registerOutputs()
             if (!worker.store.isValidPath(path)) continue;
             auto info = *worker.store.queryPathInfo(path);
             if (hash.first != info.narHash) {
-                handleDiffHook(path, actualPath, drvPath);
-
-                if (settings.keepFailed) {
+                if (settings.runDiffHook || settings.keepFailed) {
                     Path dst = worker.store.toRealPath(path + checkSuffix);
                     deletePath(dst);
                     if (rename(actualPath.c_str(), dst.c_str()))
                         throw SysError(format("renaming '%1%' to '%2%'") % actualPath % dst);
 
+                    handleDiffHook(
+                        !buildUser && !drv->isBuiltin(),
+                        buildUser ? buildUser->getUID() : getuid(),
+                        buildUser ? buildUser->getGID() : getgid(),
+                        path, dst, drvPath, tmpDir);
+
                     throw Error(format("derivation '%1%' may not be deterministic: output '%2%' differs from '%3%'")
                         % drvPath % path % dst);
                 } else
@@ -3269,7 +3282,11 @@ void DerivationGoal::registerOutputs()
                     ? fmt("output '%1%' of '%2%' differs from '%3%' from previous round", i->second.path, drvPath, prev)
                     : fmt("output '%1%' of '%2%' differs from previous round", i->second.path, drvPath);
 
-                handleDiffHook(prev, i->second.path, drvPath);
+                handleDiffHook(
+                    !buildUser && !drv->isBuiltin(),
+                    buildUser ? buildUser->getUID() : getuid(),
+                    buildUser ? buildUser->getGID() : getgid(),
+                    prev, i->second.path, drvPath, tmpDir);
 
                 if (settings.enforceDeterminism)
                     throw NotDeterministic(msg);
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index a7170566533e..0f4d3d92b866 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -914,8 +914,8 @@ void killUser(uid_t uid)
 
 /* Wrapper around vfork to prevent the child process from clobbering
    the caller's stack frame in the parent. */
-static pid_t doFork(bool allowVfork, std::function<void()> fun) __attribute__((noinline));
-static pid_t doFork(bool allowVfork, std::function<void()> fun)
+pid_t doFork(bool allowVfork, std::function<void()> fun) __attribute__((noinline));
+pid_t doFork(bool allowVfork, std::function<void()> fun)
 {
 #ifdef __linux__
     pid_t pid = allowVfork ? vfork() : fork();
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 54936a5cb10b..824a35b987e8 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -265,6 +265,8 @@ string runProgram(Path program, bool searchPath = false,
     const Strings & args = Strings(),
     const std::optional<std::string> & input = {});
 
+pid_t doFork(bool allowVfork, std::function<void()> fun);
+
 struct RunOptions
 {
     Path program;