From a45c498e4e1109e0147b46df1230db718e5bceb1 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 7 Dec 2006 00:42:30 +0000 Subject: [PATCH] * If Nix is not running as root, call the setuid helper to start the builder under the desired build user. --- src/libstore/build.cc | 58 ++++++++++++++++++++++------------- src/nix-setuid-helper/main.cc | 9 +++--- 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/libstore/build.cc b/src/libstore/build.cc index b4eded1b9..be6f93489 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -1342,11 +1342,6 @@ void DerivationGoal::startBuilder() initChild(); - /* Fill in the arguments. */ - Strings args(drv.args); - args.push_front(baseNameOf(drv.builder)); - const char * * argArr = strings2CharPtrs(args); - /* Fill in the environment. */ Strings envStrs; for (Environment::const_iterator i = env.begin(); @@ -1354,32 +1349,53 @@ void DerivationGoal::startBuilder() envStrs.push_back(i->first + "=" + i->second); const char * * envArr = strings2CharPtrs(envStrs); + Path program = drv.builder.c_str(); + std::vector args; /* careful with c_str()! */ + /* If we are running in `build-users' mode, then switch to the user we allocated above. Make sure that we drop all root privileges. Note that initChild() above has closed all file descriptors except std*, so that's safe. Also note that setuid() when run as root sets the real, effective and saved UIDs. */ - if (buildUser.getUID() != 0) { + if (buildUser.enabled()) { printMsg(lvlInfo, format("switching to uid `%1%'") % buildUser.getUID()); - - if (setgroups(0, 0) == -1) - throw SysError("cannot clear the set of supplementary groups"); - - if (setgid(buildUser.getGID()) == -1 || - getgid() != buildUser.getGID() || - getegid() != buildUser.getGID()) - throw SysError("setgid failed"); - if (setuid(buildUser.getUID()) == -1 || - getuid() != buildUser.getUID() || - geteuid() != buildUser.getUID()) - throw SysError("setuid failed"); + if (amPrivileged()) { + + if (setgroups(0, 0) == -1) + throw SysError("cannot clear the set of supplementary groups"); + + if (setgid(buildUser.getGID()) == -1 || + getgid() != buildUser.getGID() || + getegid() != buildUser.getGID()) + throw SysError("setgid failed"); + + if (setuid(buildUser.getUID()) == -1 || + getuid() != buildUser.getUID() || + geteuid() != buildUser.getUID()) + throw SysError("setuid failed"); + + } else { + /* Let the setuid helper take care of it. */ + program = nixLibexecDir + "/nix-setuid-helper"; + args.push_back(program.c_str()); + args.push_back("run-builder"); + args.push_back("nix-builder-1"); /* !!! TODO */ + args.push_back(drv.builder.c_str()); + } } + /* Fill in the arguments. */ + string builderBasename = baseNameOf(drv.builder); + args.push_back(builderBasename.c_str()); + for (Strings::iterator i = drv.args.begin(); + i != drv.args.end(); ++i) + args.push_back(i->c_str()); + args.push_back(0); + /* Execute the program. This should not return. */ - execve(drv.builder.c_str(), - (char * *) argArr, (char * *) envArr); + execve(program.c_str(), (char * *) &args[0], (char * *) envArr); throw SysError(format("executing `%1%'") % drv.builder); @@ -1484,7 +1500,7 @@ void DerivationGoal::computeClosure() build. Also, the output should be owned by the build user. */ if ((st.st_mode & (S_IWGRP | S_IWOTH)) || - (buildUser.getUID() != 0 && st.st_uid != buildUser.getUID())) + (buildUser.enabled() && st.st_uid != buildUser.getUID())) throw Error(format("suspicious ownership or permission on `%1%'; rejecting this build output") % path); #endif diff --git a/src/nix-setuid-helper/main.cc b/src/nix-setuid-helper/main.cc index bf70ee089..ea60b2800 100644 --- a/src/nix-setuid-helper/main.cc +++ b/src/nix-setuid-helper/main.cc @@ -57,7 +57,7 @@ static uid_t nameToUid(const string & userName) user. */ static void runBuilder(uid_t uidNix, const string & buildUsersGroup, const string & targetUser, - string program, int argc, char * * argv) + string program, int argc, char * * argv, char * * env) { uid_t uidTargetUser = nameToUid(targetUser); @@ -107,12 +107,11 @@ static void runBuilder(uid_t uidNix, /* Execute the program. */ std::vector args; - args.push_back(program.c_str()); for (int i = 0; i < argc; ++i) args.push_back(argv[i]); args.push_back(0); - if (execve(program.c_str(), (char * *) &args[0], 0) == -1) + if (execve(program.c_str(), (char * *) &args[0], env) == -1) throw SysError(format("cannot execute `%1%'") % program); } @@ -180,10 +179,10 @@ static void run(int argc, char * * argv) if (command == "run-builder") { /* Syntax: nix-setuid-helper run-builder - */ + */ if (argc < 4) throw Error("missing user name / program name"); runBuilder(uidNix, buildUsersGroup, - argv[2], argv[3], argc - 4, argv + 4); + argv[2], argv[3], argc - 4, argv + 4, oldEnviron); } else if (command == "fix-ownership") {