* If Nix is not running as root, call the setuid helper to start the

builder under the desired build user.
This commit is contained in:
Eelco Dolstra 2006-12-07 00:42:30 +00:00
parent 813a7c65c9
commit a45c498e4e
2 changed files with 41 additions and 26 deletions

View file

@ -1342,11 +1342,6 @@ void DerivationGoal::startBuilder()
initChild(); initChild();
/* Fill in the arguments. */
Strings args(drv.args);
args.push_front(baseNameOf(drv.builder));
const char * * argArr = strings2CharPtrs(args);
/* Fill in the environment. */ /* Fill in the environment. */
Strings envStrs; Strings envStrs;
for (Environment::const_iterator i = env.begin(); for (Environment::const_iterator i = env.begin();
@ -1354,32 +1349,53 @@ void DerivationGoal::startBuilder()
envStrs.push_back(i->first + "=" + i->second); envStrs.push_back(i->first + "=" + i->second);
const char * * envArr = strings2CharPtrs(envStrs); const char * * envArr = strings2CharPtrs(envStrs);
Path program = drv.builder.c_str();
std::vector<const char *> args; /* careful with c_str()! */
/* If we are running in `build-users' mode, then switch to /* If we are running in `build-users' mode, then switch to
the user we allocated above. Make sure that we drop the user we allocated above. Make sure that we drop
all root privileges. Note that initChild() above has all root privileges. Note that initChild() above has
closed all file descriptors except std*, so that's closed all file descriptors except std*, so that's
safe. Also note that setuid() when run as root sets safe. Also note that setuid() when run as root sets
the real, effective and saved UIDs. */ the real, effective and saved UIDs. */
if (buildUser.getUID() != 0) { if (buildUser.enabled()) {
printMsg(lvlInfo, format("switching to uid `%1%'") % buildUser.getUID()); printMsg(lvlInfo, format("switching to uid `%1%'") % buildUser.getUID());
if (setgroups(0, 0) == -1) if (amPrivileged()) {
throw SysError("cannot clear the set of supplementary groups");
if (setgid(buildUser.getGID()) == -1 || if (setgroups(0, 0) == -1)
getgid() != buildUser.getGID() || throw SysError("cannot clear the set of supplementary groups");
getegid() != buildUser.getGID())
throw SysError("setgid failed");
if (setuid(buildUser.getUID()) == -1 || if (setgid(buildUser.getGID()) == -1 ||
getuid() != buildUser.getUID() || getgid() != buildUser.getGID() ||
geteuid() != buildUser.getUID()) getegid() != buildUser.getGID())
throw SysError("setuid failed"); 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. */ /* Execute the program. This should not return. */
execve(drv.builder.c_str(), execve(program.c_str(), (char * *) &args[0], (char * *) envArr);
(char * *) argArr, (char * *) envArr);
throw SysError(format("executing `%1%'") throw SysError(format("executing `%1%'")
% drv.builder); % drv.builder);
@ -1484,7 +1500,7 @@ void DerivationGoal::computeClosure()
build. Also, the output should be owned by the build build. Also, the output should be owned by the build
user. */ user. */
if ((st.st_mode & (S_IWGRP | S_IWOTH)) || 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); throw Error(format("suspicious ownership or permission on `%1%'; rejecting this build output") % path);
#endif #endif

View file

@ -57,7 +57,7 @@ static uid_t nameToUid(const string & userName)
user. */ user. */
static void runBuilder(uid_t uidNix, static void runBuilder(uid_t uidNix,
const string & buildUsersGroup, const string & targetUser, 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); uid_t uidTargetUser = nameToUid(targetUser);
@ -107,12 +107,11 @@ static void runBuilder(uid_t uidNix,
/* Execute the program. */ /* Execute the program. */
std::vector<const char *> args; std::vector<const char *> args;
args.push_back(program.c_str());
for (int i = 0; i < argc; ++i) for (int i = 0; i < argc; ++i)
args.push_back(argv[i]); args.push_back(argv[i]);
args.push_back(0); 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); throw SysError(format("cannot execute `%1%'") % program);
} }
@ -180,10 +179,10 @@ static void run(int argc, char * * argv)
if (command == "run-builder") { if (command == "run-builder") {
/* Syntax: nix-setuid-helper run-builder <username> <program> /* Syntax: nix-setuid-helper run-builder <username> <program>
<args...> */ <arg0 arg1...> */
if (argc < 4) throw Error("missing user name / program name"); if (argc < 4) throw Error("missing user name / program name");
runBuilder(uidNix, buildUsersGroup, 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") { else if (command == "fix-ownership") {