From 5351518c75eb6efc77a096b912d2d3ea86110a0e Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Thu, 22 Jan 2026 16:22:41 +0100 Subject: [PATCH] libstore: add a diff hook helper libexec binary diff hooks use uid/gid switch functionality that is otherwise only needed for linux sandbox setup and unsupported by posix_spawn. not doing these switches inside lix core code may let us move to using posix_spawn for most process launching in the future, and for diff hooks the added overhead of a wrapper program really does not hurt at all. diff hooks are expected to be expensive in terms of output size, process launch overhead is not likely to even be noticeable. Change-Id: Ifa4b3eedef237632db3eb88d10e6469acae01f9e --- lix/libexec/meson.build | 7 ++++ lix/libexec/run-diff-hook.cc | 27 +++++++++++++++ lix/libstore/build/local-derivation-goal.cc | 37 +++++++++++---------- 3 files changed, 54 insertions(+), 17 deletions(-) create mode 100644 lix/libexec/run-diff-hook.cc diff --git a/lix/libexec/meson.build b/lix/libexec/meson.build index 8c458a51b..30e54d922 100644 --- a/lix/libexec/meson.build +++ b/lix/libexec/meson.build @@ -14,6 +14,13 @@ kill_user = executable( install_dir : libexecdir / 'lix', ) +run_diff_hook = executable( + 'run-diff-hook', + files('run-diff-hook.cc'), + install : true, + install_dir : libexecdir / 'lix', +) + run_pager = executable( 'run-pager', files('run-pager.cc'), diff --git a/lix/libexec/run-diff-hook.cc b/lix/libexec/run-diff-hook.cc new file mode 100644 index 000000000..b39721ab2 --- /dev/null +++ b/lix/libexec/run-diff-hook.cc @@ -0,0 +1,27 @@ +#include "common.hh" + +#include + +using std::literals::operator""sv; + +LIBEXEC_HELPER(3) + +int helperMain(const char * name, std::span args) noexcept +{ + const auto uid = args[0]; + const auto gid = args[1]; + const auto hook = args.subspan(2); + + DIE_UNLESS_SYS("chdir", chdir("/")); + if (gid != "-"sv) { + DIE_UNLESS_SYS("setgid", setgid(argToInt("gid", gid))); + /* Drop all other groups if we're setgid. */ + DIE_UNLESS_SYS("setgroups", setgroups(0, 0)); + } + if (uid != "-"sv) { + DIE_UNLESS_SYS("setuid", setuid(argToInt("uid", uid))); + } + + execvp(hook[0], hook.data()); + die("exec failed"); +} diff --git a/lix/libstore/build/local-derivation-goal.cc b/lix/libstore/build/local-derivation-goal.cc index db3da2c0a..dcf47e5c4 100644 --- a/lix/libstore/build/local-derivation-goal.cc +++ b/lix/libstore/build/local-derivation-goal.cc @@ -18,6 +18,7 @@ #include "lix/libutil/regex.hh" #include "lix/libutil/file-descriptor.hh" #include "lix/libutil/file-system.hh" +#include "lix/libutil/processes.hh" #include "lix/libutil/result.hh" #include "lix/libutil/topo-sort.hh" #include "lix/libutil/json.hh" @@ -41,6 +42,7 @@ #include #include +#include #include #include #include @@ -84,23 +86,24 @@ try { if (diffHookOpt && settings.runDiffHook) { auto & diffHook = *diffHookOpt; try { - auto diffRes = TRY_AWAIT(runProgram(RunOptions{ - .program = diffHook, - .searchPath = true, - .args = {tryA, tryB, drvPath, tmpDir}, - .uid = uid, - .gid = gid, - .chdir = "/" - })); - if (!statusOk(diffRes.first)) - throw ExecError(diffRes.first, - "diff-hook program '%1%' %2%", - diffHook, - statusToString(diffRes.first)); - - if (diffRes.second != "") { - printError("%1%", Uncolored(chomp(diffRes.second))); - } + auto hook = runHelper( + "run-diff-hook", + { + .args = + {uid ? std::to_string(*uid) : "-", + gid ? std::to_string(*gid) : "-", + diffHook, + tryA, + tryB, + drvPath, + tmpDir}, + .captureStdout = true, + } + ); + auto diffRes = TRY_AWAIT(hook.getStdout()->drain()); + hook.waitAndCheck(); + if (diffRes != "") + printError("%1%", Uncolored(chomp(diffRes))); } catch (Error & error) { ErrorInfo ei = error.info(); // FIXME: wrap errors.