runProgram: support gid, uid, chdir

This commit is contained in:
Graham Christensen 2019-05-11 16:35:53 -04:00
parent dde8eeb39a
commit b4a05edbfe
No known key found for this signature in database
GPG key ID: ACA1C1D120C83D5C
3 changed files with 30 additions and 22 deletions

View file

@ -465,26 +465,22 @@ void handleDiffHook(bool allowVfork, uid_t uid, uid_t gid, Path tryA, Path tryB,
{ {
auto diffHook = settings.diffHook; auto diffHook = settings.diffHook;
if (diffHook != "" && settings.runDiffHook) { if (diffHook != "" && settings.runDiffHook) {
auto wrapper = [&]() {
if (chdir("/") == -1)
throw SysError("chdir / failed");
if (setgid(gid) == -1)
throw SysError("setgid failed");
if (setgroups(0, 0) == -1)
throw SysError("setgroups failed");
if (setuid(uid) == -1)
throw SysError("setuid failed");
try { try {
auto diff = runProgram(diffHook, true, {tryA, tryB, drvPath, tmpDir}); RunOptions diffHookOptions(diffHook,{tryA, tryB, drvPath, tmpDir});
if (diff != "") diffHookOptions.searchPath = true;
printError(chomp(diff)); diffHookOptions.uid = uid;
diffHookOptions.gid = gid;
diffHookOptions.chdir = "/";
auto diffRes = runProgram(diffHookOptions);
if (!statusOk(diffRes.first))
throw ExecError(diffRes.first, fmt("diff-hook program '%1%' %2%", diffHook, statusToString(diffRes.first)));
if (diffRes.second != "")
printError(chomp(diffRes.second));
} catch (Error & error) { } catch (Error & error) {
printError("diff hook execution failed: %s", error.what()); printError("diff hook execution failed: %s", error.what());
} }
};
doFork(allowVfork, wrapper);
} }
} }

View file

@ -16,6 +16,7 @@
#include <future> #include <future>
#include <fcntl.h> #include <fcntl.h>
#include <grp.h>
#include <limits.h> #include <limits.h>
#include <pwd.h> #include <pwd.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -914,8 +915,8 @@ void killUser(uid_t uid)
/* Wrapper around vfork to prevent the child process from clobbering /* Wrapper around vfork to prevent the child process from clobbering
the caller's stack frame in the parent. */ the caller's stack frame in the parent. */
pid_t doFork(bool allowVfork, std::function<void()> fun) __attribute__((noinline)); static pid_t doFork(bool allowVfork, std::function<void()> fun) __attribute__((noinline));
pid_t doFork(bool allowVfork, std::function<void()> fun) static pid_t doFork(bool allowVfork, std::function<void()> fun)
{ {
#ifdef __linux__ #ifdef __linux__
pid_t pid = allowVfork ? vfork() : fork(); pid_t pid = allowVfork ? vfork() : fork();
@ -1025,6 +1026,16 @@ void runProgram2(const RunOptions & options)
if (source && dup2(in.readSide.get(), STDIN_FILENO) == -1) if (source && dup2(in.readSide.get(), STDIN_FILENO) == -1)
throw SysError("dupping stdin"); throw SysError("dupping stdin");
//if (options.chdir && chdir((*options.chdir).c_str()) == -1)
// throw SysError("chdir failed");
if (options.gid && setgid(*options.gid) == -1)
throw SysError("setgid failed");
/* Drop all other groups if we're setgid. */
if (options.gid && setgroups(0, 0) == -1)
throw SysError("setgroups failed");
if (options.uid && setuid(*options.uid) == -1)
throw SysError("setuid failed");
Strings args_(options.args); Strings args_(options.args);
args_.push_front(options.program); args_.push_front(options.program);

View file

@ -265,10 +265,11 @@ string runProgram(Path program, bool searchPath = false,
const Strings & args = Strings(), const Strings & args = Strings(),
const std::optional<std::string> & input = {}); const std::optional<std::string> & input = {});
pid_t doFork(bool allowVfork, std::function<void()> fun);
struct RunOptions struct RunOptions
{ {
std::optional<uid_t> uid;
std::optional<uid_t> gid;
std::optional<Path> chdir;
Path program; Path program;
bool searchPath = true; bool searchPath = true;
Strings args; Strings args;